From 8ab5902d2cb66809d478ef795a878a413dea41cc Mon Sep 17 00:00:00 2001 From: Jakob Kaivo Date: Wed, 13 Mar 2019 20:59:41 -0400 Subject: migrate to gitlab --- Makefile | 16 ++++ bc.h | 84 ++++++++++++++++++ bc.l | 75 ++++++++++++++++ bc.y | 291 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ expr.c | 128 ++++++++++++++++++++++++++ functions.c | 31 +++++++ num.c | 50 +++++++++++ ops.c | 50 +++++++++++ rel.c | 49 ++++++++++ set.c | 67 ++++++++++++++ var.c | 28 ++++++ 11 files changed, 869 insertions(+) create mode 100644 Makefile create mode 100644 bc.h create mode 100644 bc.l create mode 100644 bc.y create mode 100644 expr.c create mode 100644 functions.c create mode 100644 num.c create mode 100644 ops.c create mode 100644 rel.c create mode 100644 set.c create mode 100644 var.c 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 diff --git a/bc.h b/bc.h new file mode 100644 index 0000000..2bc9d5e --- /dev/null +++ b/bc.h @@ -0,0 +1,84 @@ +#define _XOPEN_SOURCE 700 +#include + +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 *); diff --git a/bc.l b/bc.l new file mode 100644 index 0000000..3fdb7ae --- /dev/null +++ b/bc.l @@ -0,0 +1,75 @@ +%{ +#define _XOPEN_SOURCE 700 +#include "bc.h" +#include "y.tab.h" +#include +#include +#include +int fileno(FILE *); +%} + +DIGIT [0-9A-F] +LETTER [a-z] +WHITESPACE [ \t\f\v] +MUL_OPS [*/%] + +%x COMMENT + +%% +"/*" { BEGIN COMMENT; } +"*/" { BEGIN INITIAL; } +.|\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++; } diff --git a/bc.y b/bc.y new file mode 100644 index 0000000..76666e4 --- /dev/null +++ b/bc.y @@ -0,0 +1,291 @@ +%{ +#define _XOPEN_SOURCE 700 +#define YYDEBUG 0 +#include "bc.h" +#include +#include +#include +#include +#include +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 +%token NUMBER +%token LETTER + +%nonassoc REL_OP +%right ASSIGN_OP +%left ADD_OP SUB_OP +%left MUL_OP +%right POW_OP +%nonassoc UNARY_MINUS +%nonassoc INCR_DECR + +%type expression relational_expression named_expression +%type 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; diff --git a/expr.c b/expr.c new file mode 100644 index 0000000..a485afc --- /dev/null +++ b/expr.c @@ -0,0 +1,128 @@ +#include "bc.h" +#include +#include + +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; +} diff --git a/num.c b/num.c new file mode 100644 index 0000000..086239a --- /dev/null +++ b/num.c @@ -0,0 +1,50 @@ +#include "bc.h" +#include +#include +#include + +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); +} diff --git a/ops.c b/ops.c new file mode 100644 index 0000000..0ba58ba --- /dev/null +++ b/ops.c @@ -0,0 +1,50 @@ +#include "bc.h" +#include + +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; +} diff --git a/rel.c b/rel.c new file mode 100644 index 0000000..3370ed4 --- /dev/null +++ b/rel.c @@ -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"); +} diff --git a/set.c b/set.c new file mode 100644 index 0000000..edaec9e --- /dev/null +++ b/set.c @@ -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; +} diff --git a/var.c b/var.c new file mode 100644 index 0000000..f53d5fe --- /dev/null +++ b/var.c @@ -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; +} -- cgit v1.2.1