summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile16
-rw-r--r--bc.h84
-rw-r--r--bc.l75
-rw-r--r--bc.y291
-rw-r--r--expr.c128
-rw-r--r--functions.c31
-rw-r--r--num.c50
-rw-r--r--ops.c50
-rw-r--r--rel.c49
-rw-r--r--set.c67
-rw-r--r--var.c28
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
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 <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 *);
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 <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++; }
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 <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;
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 <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;
+}
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 <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);
+}
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 <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;
+}
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;
+}