diff options
author | Jakob Kaivo <jkk@ung.org> | 2019-03-13 20:59:41 -0400 |
---|---|---|
committer | Jakob Kaivo <jkk@ung.org> | 2019-03-13 20:59:41 -0400 |
commit | 8ab5902d2cb66809d478ef795a878a413dea41cc (patch) | |
tree | a2d4f9cba84dbb481d4c988537f608c8e788f710 |
migrate to gitlab
-rw-r--r-- | Makefile | 16 | ||||
-rw-r--r-- | bc.h | 84 | ||||
-rw-r--r-- | bc.l | 75 | ||||
-rw-r--r-- | bc.y | 291 | ||||
-rw-r--r-- | expr.c | 128 | ||||
-rw-r--r-- | functions.c | 31 | ||||
-rw-r--r-- | num.c | 50 | ||||
-rw-r--r-- | ops.c | 50 | ||||
-rw-r--r-- | rel.c | 49 | ||||
-rw-r--r-- | set.c | 67 | ||||
-rw-r--r-- | var.c | 28 |
11 files changed, 869 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..218bcd9 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +.POSIX: + +CFLAGS=-g +OBJS=y.tab.o lex.yy.o num.o ops.o set.o var.o rel.o expr.o + +bc: $(OBJS) + $(CC) $(CFLAGS) $(OBJS) -o $@ -ly -ll -lm + +lex.yy.c: bc.l y.tab.h + $(LEX) bc.l + +y.tab.c y.tab.h: bc.y + $(YACC) -d bc.y + +clean: + rm -rf bc *.o y.tab.c y.tab.h lex.yy.c @@ -0,0 +1,84 @@ +#define _XOPEN_SOURCE 700 +#include <inttypes.h> + +typedef enum { + MUL, MOD, DIV, ADD, SUB, POW, NEG, + SET, SADD, SSUB, SMUL, SDIV, SMOD, SPOW, + EQ, LE, GE, NE, LT, GT, + INC, DEC +} bc_op; + +typedef enum { + DEFINE, BREAK, QUIT, LENGTH, + RETURN, FOR, IF, WHILE, SQRT, + SCALE, IBASE, OBASE, AUTO +} bc_kw; + +typedef struct { + int scale; + intmax_t n; +} bc_num; + +typedef struct bc_expression { + enum bc_expression_type { + NAMED, LITERAL, FUNCTION_CALL, OPERATION + } type; + char letter; + struct bc_expression *left; + struct bc_expression *right; + bc_num *literal; + bc_num *lval; + bc_num *rval; + bc_op op; +} bc_expression; + +extern int bc_lineno; +extern int bc_char; + +bc_num *bc_eval(bc_expression *); +bc_expression *bc_named(char); +bc_expression *bc_literal(bc_num *); +bc_expression *bc_function_call(char, void*); +bc_expression *bc_operation(bc_op, bc_expression *, bc_expression *); + +bc_num *bc_new(const char *); +void bc_free(bc_num *); +bc_num *bc_print(bc_num *); +int bc_toint(bc_num *); + +/* basic operations */ +bc_num *bc_mul(bc_num *, bc_num *); +bc_num *bc_add(bc_num *, bc_num *); +bc_num *bc_sub(bc_num *, bc_num *); +bc_num *bc_div(bc_num *, bc_num *); +bc_num *bc_mod(bc_num *, bc_num *); +bc_num *bc_pow(bc_num *, bc_num *); +bc_num *bc_neg(bc_num *); + +/* modifying operations */ +bc_num *bc_inc(bc_num *); +bc_num *bc_dec(bc_num *); +bc_num *bc_set(bc_num *, bc_num *); +bc_num *bc_sadd(bc_num *, bc_num *); +bc_num *bc_ssub(bc_num *, bc_num *); +bc_num *bc_smul(bc_num *, bc_num *); +bc_num *bc_sdiv(bc_num *, bc_num *); +bc_num *bc_smod(bc_num *, bc_num *); +bc_num *bc_spow(bc_num *, bc_num *); + +/* relation operations */ +bc_num *bc_eq(bc_num *, bc_num *); +bc_num *bc_le(bc_num *, bc_num *); +bc_num *bc_ge(bc_num *, bc_num *); +bc_num *bc_ne(bc_num *, bc_num *); +bc_num *bc_lt(bc_num *, bc_num *); +bc_num *bc_gt(bc_num *, bc_num *); + +/* variables */ +bc_num *bc_let(char); +bc_num *bc_arr(char, bc_num *); + +/* built-in functions */ +bc_num *bc_length(bc_num *); +bc_num *bc_sqrt(bc_num *); +bc_num *bc_scale(bc_num *); @@ -0,0 +1,75 @@ +%{ +#define _XOPEN_SOURCE 700 +#include "bc.h" +#include "y.tab.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +int fileno(FILE *); +%} + +DIGIT [0-9A-F] +LETTER [a-z] +WHITESPACE [ \t\f\v] +MUL_OPS [*/%] + +%x COMMENT + +%% +"/*" { BEGIN COMMENT; } +<COMMENT>"*/" { BEGIN INITIAL; } +<COMMENT>.|\n ; + +{DIGIT}+ { bc_char += strlen(yytext); yylval.num = bc_new(yytext); return NUMBER; } +\.{DIGIT}+ { bc_char += strlen(yytext); yylval.num = bc_new(yytext); return NUMBER; } +{DIGIT}+\. { bc_char += strlen(yytext); yylval.num = bc_new(yytext); return NUMBER; } +{DIGIT}+\.{DIGIT}+ { bc_char += strlen(yytext); yylval.num = bc_new(yytext); return NUMBER; } + +"*" { bc_char += strlen(yytext); yylval.op = MUL; return MUL_OP; } +"%" { bc_char += strlen(yytext); yylval.op = MOD; return MUL_OP; } +"\/" { bc_char += strlen(yytext); yylval.op = DIV; return MUL_OP; } + +"+" { bc_char += strlen(yytext); yylval.op = ADD; return ADD_OP; } +"-" { bc_char += strlen(yytext); yylval.op = SUB; return SUB_OP; } +"^" { bc_char += strlen(yytext); yylval.op = POW; return POW_OP; } + +"=" { bc_char += strlen(yytext); yylval.op = SET; return ASSIGN_OP; } +"+=" { bc_char += strlen(yytext); yylval.op = SADD; return ASSIGN_OP; } +"-=" { bc_char += strlen(yytext); yylval.op = SSUB; return ASSIGN_OP; } +"*=" { bc_char += strlen(yytext); yylval.op = SMUL; return ASSIGN_OP; } +"\/=" { bc_char += strlen(yytext); yylval.op = SDIV; return ASSIGN_OP; } +"%=" { bc_char += strlen(yytext); yylval.op = SMOD; return ASSIGN_OP; } +"^=" { bc_char += strlen(yytext); yylval.op = SPOW; return ASSIGN_OP; } + +"==" { bc_char += strlen(yytext); yylval.op = EQ; return REL_OP; } +"<=" { bc_char += strlen(yytext); yylval.op = LE; return REL_OP; } +">=" { bc_char += strlen(yytext); yylval.op = GE; return REL_OP; } +"!=" { bc_char += strlen(yytext); yylval.op = NE; return REL_OP; } +"<" { bc_char += strlen(yytext); yylval.op = LT; return REL_OP; } +">" { bc_char += strlen(yytext); yylval.op = GT; return REL_OP; } + +"++" { bc_char += strlen(yytext); yylval.op = INC; return INCR_DECR; } +"--" { bc_char += strlen(yytext); yylval.op = DEC; return INCR_DECR; } + +"define" { bc_char += strlen(yytext); return Define; } +"break" { bc_char += strlen(yytext); return Break; } +"quit" { bc_char += strlen(yytext); return Quit; } +"length" { bc_char += strlen(yytext); return Length; } +"return" { bc_char += strlen(yytext); return Return; } +"for" { bc_char += strlen(yytext); return For; } +"if" { bc_char += strlen(yytext); return If; } +"while" { bc_char += strlen(yytext); return While; } +"sqrt" { bc_char += strlen(yytext); return Sqrt; } +"scale" { bc_char += strlen(yytext); return Scale; } +"ibase" { bc_char += strlen(yytext); return Ibase; } +"obase" { bc_char += strlen(yytext); return Obase; } +"auto" { bc_char += strlen(yytext); return Auto; } + +"\n" { bc_lineno++; bc_char = 1; return NEWLINE; } + +\(|\)|\[|\]|;|, { bc_char++; return yytext[0]; } + +{LETTER} { bc_char++; yylval.c = yytext[0]; return LETTER; } + +{WHITESPACE} { bc_char++; } +. { bc_char++; } @@ -0,0 +1,291 @@ +%{ +#define _XOPEN_SOURCE 700 +#define YYDEBUG 0 +#include "bc.h" +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +int yyerror(const char *); +int yylex(void); +extern FILE *yyin; +%} + +%union { + bc_expression *expr; + bc_num *num; + bc_op op; + char c; + char *string; + int truth; +} + +%token ENDOFFILE 0 +%token NEWLINE + +%token Define Break Quit Length +%token Return For If While Sqrt +%token Scale Ibase Obase Auto + +%token<string> STRING +%token<num> NUMBER +%token<c> LETTER + +%nonassoc<op> REL_OP +%right<op> ASSIGN_OP +%left<op> ADD_OP SUB_OP +%left<op> MUL_OP +%right<op> POW_OP +%nonassoc UNARY_MINUS +%nonassoc<op> INCR_DECR + +%type<expr> expression relational_expression named_expression +%type<num> statement semicolon_list return_expression statement_list + +%start program + +%% + +program + : ENDOFFILE + | input_item program +; + +input_item + : semicolon_list NEWLINE { + } + | function +; + +semicolon_list + : /* empty */ + | statement + | semicolon_list ';' statement { + bc_print(bc_eval($1)); + bc_print(bc_eval($3)); + } + | semicolon_list ';' { + bc_print(bc_eval($1)); + } +; + +statement_list + : /* empty */ + | statement + | statement_list NEWLINE + | statement_list NEWLINE statement + | statement_list ';' + | statement_list ';' statement +; + +statement + : expression { + } + | STRING { + } + | Break { + } + | Quit { + exit(0); + } + | Return { + } + | Return '(' return_expression ')' { + } + | For '(' expression ';' relational_expression ';' expression ')' statement { + } + | If '(' relational_expression ')' statement { + } + | While '(' relational_expression ')' statement { + } + | '{' statement_list '}' { + } +; + +function + : Define LETTER '(' opt_parameter_list ')' '{' NEWLINE opt_auto_define_list statement_list '}' +; + +opt_parameter_list + : /* empty */ + | parameter_list +; + +parameter_list + : LETTER + | define_list ',' LETTER +; + +opt_auto_define_list + : /* empty */ + | Auto define_list NEWLINE + | Auto define_list ';' +; + +define_list + : LETTER + | LETTER '[' ']' + | define_list ',' LETTER + | define_list ',' LETTER '[' ']' +; + +opt_argument_list + : /* empty */ + | argument_list +; + +argument_list + : expression + | LETTER '[' ']' ',' argument_list +; + +relational_expression + : expression { + $$ = $1; + } + | expression REL_OP expression { + $$ = bc_operation($2, $1, $3); + } +; + +return_expression + : /* empty */ + | expression +; + +expression + : named_expression + | NUMBER { + $$ = bc_literal($1); + } + | '(' expression ')' { + $$ = $2; + } + | LETTER '(' opt_argument_list ')' { + $$ = bc_function_call($1, NULL); + } + | SUB_OP expression %prec UNARY_MINUS { + $$ = bc_operation(NEG, $2, NULL); + } + | expression ADD_OP expression { + $$ = bc_operation(ADD, $1, $3); + } + | expression SUB_OP expression { + $$ = bc_operation(ADD, $1, $3); + } + | expression MUL_OP expression { + $$ = bc_operation($2, $1, $3); + } + | expression POW_OP expression { + $$ = bc_operation(POW, $1, $3); + } + | INCR_DECR named_expression { + $$ = bc_operation($1, $2, NULL); + } + | named_expression INCR_DECR { + $$ = bc_operation($2, $1, NULL); + } + | named_expression ASSIGN_OP expression { + $$ = bc_operation($2, $1, $3); + } + | Length '(' expression ')' { + $$ = bc_function_call('L', $3); + } + | Sqrt '(' expression ')' { + $$ = bc_function_call('R', $3); + } + | Scale '(' expression ')' { + $$ = bc_function_call('S', $3); + } +; + +named_expression + : LETTER { + $$ = bc_named($1); + } + | LETTER '[' expression ']' { + } + | Scale { + $$ = bc_named('S'); + } + | Ibase { + $$ = bc_named('I'); + } + | Obase { + $$ = bc_named('O'); + } +; +%% +static char **files; + +int yywrap(void) +{ + char *file = files[optind++]; + + if (yyin != stdin) { + fclose(yyin); + } + + if (file == NULL) { + return 1; + } + + yyin = strcmp(file, "-") ? fopen(file, "r") : stdin; + + if (yyin == NULL) { + fprintf(stderr, "bc: Couldn't open %s: %s\n", file, strerror(errno)); + exit(1); + } + + bc_lineno = 1; + bc_char = 1; + + return 0; +} + +int yyerror(const char *str) +{ + if (!feof(yyin)) { + fprintf(stderr, "%s at line %d, character %d\n", str, bc_lineno, bc_char); + } + + if (isatty(fileno(yyin))) { + /* recover */ + return 1; + } + + exit(1); +} + +int main(int argc, char *argv[]) +{ + int c; + while ((c = getopt(argc, argv, "l")) != -1) { + switch (c) { + case 'l': /** enable math functions and set /scale/ to 20 **/ + /* set scale = 20 */ + /* load math functions */ + break; + + default: + return 1; + } + } + + #if YYDEBUG == 1 + yydebug = 1; + #endif + + yyin = stdin; + + if (argv[optind] != NULL) { + files = argv; + yywrap(); + } + + return yyparse(); +} + +int bc_lineno = 1; +int bc_char = 1; @@ -0,0 +1,128 @@ +#include "bc.h" +#include <stdio.h> +#include <stdlib.h> + +static bc_expression *newexp(enum bc_expression_type t) +{ + bc_expression *e = calloc(1, sizeof (*e)); + if (e == NULL) { + perror("bc: out of memory:"); + exit(1); + } + e->type = t; + return e; +} + +void freeexp(bc_expression *exp) +{ + if (exp->lval) { + bc_free(exp->lval); + } + if (exp->rval) { + bc_free(exp->rval); + } +/* + if (exp->literal) { + bc_free(exp->literal); + } +*/ + if (exp->left) { + freeexp(exp->left); + } + if (exp->right) { + freeexp(exp->right); + } + free(exp); +} + +bc_num *bc_eval(bc_expression *exp) +{ + bc_num *r = NULL; + + if (exp->left) { + exp->lval = bc_eval(exp->left); + } + + if (exp->right) { + exp->rval = bc_eval(exp->right); + } + + switch (exp->type) { + case NAMED: + r = bc_let(exp->letter); + break; + + case LITERAL: + r = exp->literal; + break; + + case FUNCTION_CALL: + r = NULL; + break; + + case OPERATION: + switch (exp->op) { + case MUL: r = bc_mul(exp->lval, exp->rval); break; + case DIV: r = bc_div(exp->lval, exp->rval); break; + case ADD: r = bc_add(exp->lval, exp->rval); break; + case SUB: r = bc_sub(exp->lval, exp->rval); break; + case MOD: r = bc_mod(exp->lval, exp->rval); break; + case POW: r = bc_pow(exp->lval, exp->rval); break; + + case SET: r = bc_set(exp->lval, exp->rval); break; + case SADD: r = bc_sadd(exp->lval, exp->rval); break; + case SSUB: r = bc_ssub(exp->lval, exp->rval); break; + case SMUL: r = bc_smul(exp->lval, exp->rval); break; + case SDIV: r = bc_sdiv(exp->lval, exp->rval); break; + case SMOD: r = bc_smod(exp->lval, exp->rval); break; + case SPOW: r = bc_spow(exp->lval, exp->rval); break; + + case EQ: r = bc_eq(exp->lval, exp->rval); break; + case LE: r = bc_le(exp->lval, exp->rval); break; + case GE: r = bc_ge(exp->lval, exp->rval); break; + case NE: r = bc_ne(exp->lval, exp->rval); break; + case LT: r = bc_lt(exp->lval, exp->rval); break; + case GT: r = bc_gt(exp->lval, exp->rval); break; + + case NEG: r = bc_neg(exp->lval); break; + case INC: r = bc_inc(exp->lval); break; + case DEC: r = bc_dec(exp->lval); break; + } + break; + } + + free(exp); + + return r; +} + +bc_expression *bc_named(char letter) +{ + bc_expression *e = newexp(NAMED); + e->letter = letter; + return e; +} + +bc_expression *bc_literal(bc_num *n) +{ + bc_expression *e = newexp(LITERAL); + e->literal = n; + return e; +} + +bc_expression *bc_function_call(char letter, void *arg) +{ + bc_expression *e = newexp(FUNCTION_CALL); + e->letter = letter; + e->literal = arg; + return e; +} + +bc_expression *bc_operation(bc_op op, bc_expression *left, bc_expression *right) +{ + bc_expression *e = newexp(OPERATION); + e->op = op; + e->left = left; + e->right = right; + return e; +} diff --git a/functions.c b/functions.c new file mode 100644 index 0000000..d0129fd --- /dev/null +++ b/functions.c @@ -0,0 +1,31 @@ +#include "bc.h" + +bc_num *bc_sin(bc_num *x) +{ + return x; +} + +bc_num *bc_cos(bc_num *x) +{ + return x; +} + +bc_num *bc_atan(bc_num *x) +{ + return x; +} + +bc_num *bc_log(bc_num *x) +{ + return x; +} + +bc_num *bc_exp(bc_num *x) +{ + return x; +} + +bc_num *bc_jn(bc_num *x, bc_num *y) +{ + return x; +} @@ -0,0 +1,50 @@ +#include "bc.h" +#include <math.h> +#include <stdlib.h> +#include <stdio.h> + +bc_num zero; + +bc_num *bc_new(const char *str) +{ + if (str == NULL) { + return &zero; + } + + bc_num *num = calloc(1, sizeof(*num)); + num->n = atoi(str); + return num; +} + +int bc_toint(bc_num *num) +{ + return num->n; +} + +bc_num *bc_print(bc_num *num) +{ + printf("%"PRIdMAX"\n", num->n); + return num; +} + +bc_num *bc_length(bc_num *a) +{ + return a; +} + +bc_num *bc_sqrt(bc_num *a) +{ + bc_num *root = calloc(1, sizeof(*root)); + root->n = sqrt(a->n); + return root; +} + +bc_num *bc_scale(bc_num *a) +{ + return a; +} + +void bc_free(bc_num *n) +{ + free(n); +} @@ -0,0 +1,50 @@ +#include "bc.h" +#include <stdlib.h> + +bc_num *bc_mul(bc_num *a, bc_num *b) +{ + bc_num *num = calloc(1, sizeof(*num)); + num->n = a->n * b->n; + return num; +} + +bc_num *bc_div(bc_num *a, bc_num *b) +{ + bc_num *num = calloc(1, sizeof(*num)); + num->n = a->n / b->n; + return num; +} + +bc_num *bc_mod(bc_num *a, bc_num *b) +{ + bc_num *num = calloc(1, sizeof(*num)); + num->n = a->n % b->n; + return num; +} + +bc_num *bc_add(bc_num *a, bc_num *b) +{ + bc_num *num = calloc(1, sizeof(*num)); + num->n = a->n + b->n; + return num; +} + +bc_num *bc_sub(bc_num *a, bc_num *b) +{ + bc_num *num = calloc(1, sizeof(*num)); + num->n = a->n - b->n; + return num; +} + +bc_num *bc_pow(bc_num *a, bc_num *b) +{ + bc_num *num = calloc(1, sizeof(*num)); + /* raise a^b */ + return num; +} + +bc_num *bc_neg(bc_num *a) +{ + a->n = - a->n; + return a; +} @@ -0,0 +1,49 @@ +#include "bc.h" + +bc_num *bc_eq(bc_num *a, bc_num *b) +{ + if (a->n == b->n) { + return bc_new("1"); + } + return bc_new("0"); +} + +bc_num *bc_lt(bc_num *a, bc_num *b) +{ + if (a->n < b->n) { + return bc_new("1"); + } + return bc_new("0"); +} + +bc_num *bc_gt(bc_num *a, bc_num *b) +{ + if (a->n > b->n) { + return bc_new("1"); + } + return bc_new("0"); +} + +bc_num *bc_le(bc_num *a, bc_num *b) +{ + if (a->n <= b->n) { + return bc_new("1"); + } + return bc_new("0"); +} + +bc_num *bc_ge(bc_num *a, bc_num *b) +{ + if (a->n >= b->n) { + return bc_new("1"); + } + return bc_new("0"); +} + +bc_num *bc_ne(bc_num *a, bc_num *b) +{ + if (a->n != b->n) { + return bc_new("1"); + } + return bc_new("0"); +} @@ -0,0 +1,67 @@ +#include "bc.h" + +bc_num *bc_set(bc_num *a, bc_num *b) +{ + a->n = b->n; + return a; +} + +bc_num *bc_inc(bc_num *a) +{ + a->n++; + return a; +} + +bc_num *bc_dec(bc_num *a) +{ + a->n--; + return a; +} + +bc_num *bc_sadd(bc_num *a, bc_num *b) +{ + bc_num *tmp = bc_add(a, b); + bc_set(a, tmp); + bc_free(tmp); + return a; +} + +bc_num *bc_ssub(bc_num *a, bc_num *b) +{ + bc_num *tmp = bc_sub(a, b); + bc_set(a, tmp); + bc_free(tmp); + return a; +} + +bc_num *bc_smul(bc_num *a, bc_num *b) +{ + bc_num *tmp = bc_mul(a, b); + bc_set(a, tmp); + bc_free(tmp); + return a; +} + +bc_num *bc_sdiv(bc_num *a, bc_num *b) +{ + bc_num *tmp = bc_div(a, b); + bc_set(a, tmp); + bc_free(tmp); + return a; +} + +bc_num *bc_smod(bc_num *a, bc_num *b) +{ + bc_num *tmp = bc_mod(a, b); + bc_set(a, tmp); + bc_free(tmp); + return a; +} + +bc_num *bc_spow(bc_num *a, bc_num *b) +{ + bc_num *tmp = bc_pow(a, b); + bc_set(a, tmp); + bc_free(tmp); + return a; +} @@ -0,0 +1,28 @@ +#include "bc.h" + +bc_num *bc_let(char letter) +{ + static bc_num variables[26] = {0}; + static bc_num scale; + static bc_num ibase; + static bc_num obase; + + if (letter == 'S') { + return &scale; + } + + if (letter == 'I') { + return &ibase; + } + + if (letter == 'O') { + return &obase; + } + + return variables + (letter - 'a'); +} + +bc_num *bc_arr(char c, bc_num *a) +{ + return a; +} |