diff --git a/.gitignore b/.gitignore index b1b7b45..31fcf21 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ calc.c # ignore compiled parser calc + +a.out diff --git a/calc.leg b/calc.leg index 8a4d8c4..6ae6df3 100644 --- a/calc.leg +++ b/calc.leg @@ -6,9 +6,115 @@ * run: echo "2+3" | ./calc */ -#define YYSTYPE int -YYSTYPE yylval = 0; -int var[26]; +#include + +union u_t { + int ival; + char *sval; +}; +#define YYSTYPE union u_t +YYSTYPE yylval; + +#define SYMBOL_TABLE_CHUNK 1024 + +typedef struct symbol_t { + char *ident; + bool defined; + int value; +} symbol_t; + +typedef struct table_t { + symbol_t **array; + int size; + int capacity; +} table_t; + +table_t table; + +typedef struct bsearch_t { + int pos; + bool found; +} bsearch_t; + +char *ident_buf; + +bsearch_t binary_search(symbol_t *arr[], int l, int r, char *ident) +{ + while (r >= l) { + int mid = l + (r - l) / 2; + int cmpres = strcmp(arr[mid]->ident, ident); + if (cmpres > 0) { + r = mid - 1; + } else if (cmpres < 0) { + l = mid + 1; + } else { + bsearch_t res = { mid, true }; + return res; + } + } + bsearch_t res = { l, false }; + return res; +} + +int insert(table_t *table, symbol_t *element, int pos) +{ + if (pos < 0 || pos > table->size) { + return -1; + } + + if (table->size >= table->capacity) { + table->array = realloc(table->array, sizeof(symbol_t *) * (table->capacity + SYMBOL_TABLE_CHUNK)); + if (table->array == NULL) { + printf("Error: running out of memory\n"); + exit(1); + } + table->capacity += SYMBOL_TABLE_CHUNK; + } + + for (int i = table->size; i > pos; i--) { + table->array[i] = table->array[i-1]; + } + table->array[pos] = element; + return ++(table->size); +} + +symbol_t *intern(char *ident, bool create) +{ + bsearch_t res = binary_search(table.array, 0, table.size - 1, ident); + if (res.found) { + return table.array[res.pos]; + } + + if (create) { + symbol_t *new_symbol = malloc(sizeof(symbol_t)); + new_symbol->ident = strdup(ident); + new_symbol->defined = false; + insert(&table, new_symbol, res.pos); + return new_symbol; + } else { + return NULL; + } +} + +symbol_t *update_value(symbol_t * s, int value) +{ + s->value = value; + s->defined = true; + return s; +} + + +void init_table() +{ + table.array = malloc(sizeof(symbol_t *) * SYMBOL_TABLE_CHUNK); + if (table.array == NULL) { + printf("Error: running out of memory\n"); + exit(1); + } + table.size = 0; + table.capacity = SYMBOL_TABLE_CHUNK; +} + %} @@ -18,49 +124,44 @@ exp = - (a:assign { $$ = a } | s:sum { $$ = s } ) -assign = l:LETTER EQUAL n:sum { $$ = var[l - 'a'] = n } +assign = l:IDENT { ident_buf = strdup(l.sval) } + EQUAL n:sum { symbol_t *nsymb = intern(ident_buf, true); $$.ival = update_value(nsymb, n.ival)->value; free(ident_buf) } sum = PLUS* l:prod - ( PLUS+ r:prod { l += r } - | MINUS r:prod { l -= r } - )* { $$ = l } + ( PLUS+ r:prod { l.ival += r.ival } + | MINUS r:prod { l.ival -= r.ival } + )* { $$.ival = l.ival } prod = l:neg - ( MULTI r:neg { l *= r } - | DIVIDE r:neg { l /= r } - | MODULO r:neg { l %= r } - )* { $$ = l } + ( MULTI r:neg { l.ival *= r.ival } + | DIVIDE r:neg { l.ival /= r.ival } + | MODULO r:neg { l.ival %= r.ival } + )* { $$.ival = l.ival } -neg = MINUS n:neg { $$ = -n } - | n:value { $$ = n } +neg = MINUS n:neg { $$.ival = -n.ival } + | n:value { $$.ival = n.ival } -value = n:NUMBER { $$ = n } - | l:LETTER { $$ = var[l - 'a'] } +value = n:NUMBER { $$.ival = n.ival } + | l:IDENT { symbol_t *fsymb = intern(l.sval, false); $$.ival = (fsymb != NULL) ? (fsymb->defined == true) ? fsymb->value : 0 : 0 } - = [ \t]* -NUMBER = < [0-9]+ > - { $$ = atoi(yytext) } +NUMBER = < [0-9]+ > - { $$.ival = atoi(yytext) } PLUS = '+' - MINUS = '-' - MULTI = '*' - DIVIDE = '/' - MODULO = '%' - -LETTER = (< [a-z] > { $$ = yytext[0] } - |< [A-Z] > { $$ = yytext[0] + 'a' - 'A' } - ) - EQUAL = '=' - +IDENT = < [a-zA-Z]+ > - { $$.sval = yytext } %% int main(int argc, char **argv) { + init_table(); while (yyparse()) { - printf("%d\n", yylval); - } - /* - for (int i = 0; i < 26; i++) { - printf("var[%d]=%d ", i, var[i]); + printf("%d\n", yylval.ival); } - */ return 0; } diff --git a/draft.c b/draft.c new file mode 100644 index 0000000..78d884e --- /dev/null +++ b/draft.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#define SYMBOL_TABLE_CHUNK 4 + +typedef struct symbol_t { + char *ident; + bool defined; + int value; +} symbol_t; + +typedef struct table_t { + symbol_t **array; + int size; + int capacity; +} table_t; + +table_t table; + +typedef struct bsearch_t { + int pos; + bool found; +} bsearch_t; + +bsearch_t binary_search(symbol_t *arr[], int l, int r, char *ident) +{ + while (r >= l) { + int mid = l + (r - l) / 2; + int cmpres = strcmp(arr[mid]->ident, ident); + if (cmpres > 0) { + r = mid - 1; + } else if (cmpres < 0) { + l = mid + 1; + } else { + bsearch_t res = { mid, true }; + return res; + } + } + bsearch_t res = { l, false }; + return res; +} + +int insert(table_t *table, symbol_t *element, int pos) +{ + if (pos < 0 || pos > table->size) { + return -1; + } + + if (table->size >= table->capacity) { + table->array = realloc(table->array, sizeof(symbol_t *) * (table->capacity + SYMBOL_TABLE_CHUNK)); + if (table->array == NULL) { + printf("Error: running out of memory\n"); + exit(1); + } + table->capacity += SYMBOL_TABLE_CHUNK; + } + + for (int i = table->size; i > pos; i--) { + table->array[i] = table->array[i-1]; + } + table->array[pos] = element; + return ++(table->size); +} + +symbol_t *intern(char *ident, bool create) +{ + bsearch_t res = binary_search(table.array, 0, table.size - 1, ident); + printf("pos:%d\n", res.pos); + if (res.found) { + return table.array[res.pos]; + } + + if (create) { + symbol_t *new_symbol = malloc(sizeof(symbol_t)); + new_symbol->ident = strdup(ident); + new_symbol->defined = false; + printf("insert:%d\n", insert(&table, new_symbol, res.pos)); + return new_symbol; + } else { + return NULL; + } +} + +void init_table() +{ + table.array = malloc(sizeof(symbol_t *) * SYMBOL_TABLE_CHUNK); + if (table.array == NULL) { + printf("Error: running out of memory\n"); + exit(1); + } + table.size = 0; + table.capacity = SYMBOL_TABLE_CHUNK; +} + +symbol_t *update_value(symbol_t * s, int value) +{ + s->value = value; + s->defined = true; + return s; +} + +int main() +{ + init_table(); + char line[256]; + intern("chaussure\n", true); + while (fgets(line, sizeof(line), stdin)) { + printf("intern:%p\n", intern(line, true)); + printf("after size:%d\n", table.size); + printf("after capacity:%d\n", table.capacity); + printf("\n"); + for (int i = 0; i < table.size; i++) { + printf("%d.%s", i, table.array[i]->ident); + } + printf("\n"); + } +} \ No newline at end of file diff --git a/test.sh b/test.sh index 0e36626..48ba5a7 100755 --- a/test.sh +++ b/test.sh @@ -17,6 +17,7 @@ echo "-3*2+10*2" | ./${PROG} | cmp <(echo "14") && echo "test#11 passed!" || tru echo "- 5% 2 +2-6 / 2" | ./${PROG} | cmp <(echo "-2") && echo "test#12 passed!" || true echo "a=3" | ./${PROG} | cmp <(echo "3") && echo "test#13 passed!" || true echo "a=3 a*2" | ./${PROG} | cmp <(printf "3\n6\n") && echo "test#14 passed!" || true -echo "a=10 z=13 A+z" | ./${PROG} | cmp <(printf "10\n13\n23\n") && echo "test#15 passed!" || true +echo "a=10 z=13 a+z" | ./${PROG} | cmp <(printf "10\n13\n23\n") && echo "test#15 passed!" || true +echo "tamales=10 tomato=2 tamales*tomato" | ./${PROG} | cmp <(printf "10\n2\n20\n") && echo "test#16 passed!" || true make clean \ No newline at end of file