From b0f59db5cfd84053551ae2e272c06a0f84ad1fa0 Mon Sep 17 00:00:00 2001 From: mtardy Date: Tue, 28 Jul 2020 01:37:24 +0200 Subject: [PATCH] Add Objects with prototypes --- .gitignore | 3 + Makefile | 7 +- object.c | 31 +++++++ parse.leg | 236 ++++++++++++++++++++++++++++++++++++++++++++++++ test.txt | 5 + tests/test3.txt | 6 -- 6 files changed, 280 insertions(+), 8 deletions(-) create mode 100644 parse.leg create mode 100644 test.txt delete mode 100644 tests/test3.txt diff --git a/.gitignore b/.gitignore index 78b6983..59d41f4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ calc.c calc calc.dSYM/ +parse.c +parse +parse.dSYM/ NOTES.txt a.out diff --git a/Makefile b/Makefile index 31d5035..b3a9208 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,11 @@ LDLIBS = -L/usr/local/lib -lgc # moved LDLIBS to end because ld scans files from left to right and collects only required symbols -calc: calc.c object.c - $(CC) $(CFLAGS) -o calc calc.c $(LDLIBS) +calc: parse.c object.c + $(CC) $(CFLAGS) -o parse parse.c $(LDLIBS) + +parse.c: parse.leg + $(LEG) -o parse.c parse.leg calc.c: calc.leg $(LEG) -o calc.c calc.leg diff --git a/object.c b/object.c index 6df578a..81563d7 100644 --- a/object.c +++ b/object.c @@ -259,6 +259,32 @@ oop map_append(oop map, oop value) return map_set(map, makeInteger(get(map, Map, size)), value); } +void print(oop ast); + +void map_print(oop map, int ident) +{ + assert(is(Map, map)); + if (ident > 1) { + printf("\n"); + } + for (size_t i = 0; i < get(map, Map, size); i++) { + for (size_t i = 0; i < ident; i++) { + printf("\t"); + } + // todo: a key could be a map itself + print(get(map, Map, elements)[i].key); + printf(": "); + oop rhs = get(map, Map, elements)[i].value; + if (rhs->type == Map) { + map_print(rhs, ident + 1); + } else { + print(rhs); + } + if (i < get(map, Map, size) - 1) printf(",\n"); + } + return; +} + void print(oop ast) { assert(ast); @@ -279,6 +305,7 @@ void print(oop ast) printf("Function@%p", get(ast, Function, primitive)); return; case Map: + /* printf("{"); for (size_t i = 0; i < get(ast, Map, size); i++) { printf(" "); @@ -291,6 +318,10 @@ void print(oop ast) else printf(" "); } printf("}"); + */ + printf("{\n"); + map_print(ast, 1); + printf("\n}"); return; } assert(0); diff --git a/parse.leg b/parse.leg new file mode 100644 index 0000000..e7da04c --- /dev/null +++ b/parse.leg @@ -0,0 +1,236 @@ +%{ + +/* compile: leg -o parse.c parse.leg + * cc -o parse parse.c + * + * run: echo "3+4" | ./parse + */ + +#include "object.c" + +// this is the global scope +oop globals; + +oop apply(oop function, oop parameters) +{ + return get(function, Function, primitive)(parameters); +} + +#define YYSTYPE oop + +YYSTYPE yylval; + +%} + +start = - e:exp { yylval = e } + +exp = l:IDENT EQUAL p:exp { $$ = map_set(globals, l, p) } + | l:postfix DOT i:IDENT EQUAL p:exp { $$ = map_set(l, i, p) } + | l:postfix LBRAC i:exp RBRAC EQUAL p:exp { $$ = map_set(l, i, p) } + | s:sum { $$ = s } + +sum = l:prod + ( PLUS+ r:prod { get(l, Integer, value) += get(r, Integer, value) } + | MINUS r:prod { get(l, Integer, value) -= get(r, Integer, value) } + )* { $$ = l } + +prod = l:prefix + ( MULTI r:prefix { get(l, Integer, value) *= get(r, Integer, value) } + | DIVIDE r:prefix { get(l, Integer, value) /= get(r, Integer, value) } + | MODULO r:prefix { get(l, Integer, value) %= get(r, Integer, value) } + )* { $$ = l } + +prefix = MINUS n:prefix { set(n, Integer, value, -get(n, Integer, value)); $$ = n } + | PLUS n:prefix { $$ = n } + | n:postfix { $$ = n } + +postfix = i:value ( DOT s:IDENT p:parameterList { map_set(p, intern("this"), i); i = apply(map_get(i, s), p) } + | DOT s:IDENT !EQUAL { i = map_get(i, s) } + | LBRAC p:exp RBRAC !EQUAL { i = map_get(i, p) } + | p:parameterList { i = apply(i, p) } + ) * { $$ = i } + +parameterList = LPAREN m:makeMap + ( e:exp { map_append(m, e) } + ( COMMA e:exp { map_append(m, e) } + ) * + ) ? + RPAREN { $$ = m } + +value = n:NUMBER { $$ = n } + | s:string { $$ = s } + | s:symbol { $$ = s } + | m:map { $$ = m } + | NULL { $$ = null } + | i:IDENT { $$ = map_get(globals, i) } + | LPAREN i:exp RPAREN { $$ = i } + +string = SQUOTE < (!SQUOTE .)* > SQUOTE { $$ = makeString(yytext) } + | DQUOTE < (!DQUOTE .)* > DQUOTE { $$ = makeString(yytext) } + +symbol = HASH ( i:IDENT { $$ = i } + | i:string { $$ = intern(get(i, String, value)) } + ) + +map = LCB m:makeMap + ( k:IDENT COLON v:exp { map_set(m, k, v) } + ( COMMA k:IDENT COLON v:exp { map_set(m, k, v) } + ) * + ) ? + RCB { $$ = m } + +makeMap = { $$ = makeMap() } + +- = [ \t\n\r]* + | "//" ( ![\n\r] . )* + +IDENT = < [a-zA-Z][a-zA-Z0-9_]* > - { $$ = intern(yytext) } +NUMBER = < [0-9]+ > - { $$ = makeInteger(atoi(yytext)) } +HASH = '#' - +PLUS = '+' - +MINUS = '-' - +MULTI = '*' - +DIVIDE = '/' - +MODULO = '%' - +EQUAL = '=' - +NULL = 'null' - +COLON = ':' - +COMMA = ',' - +DOT = '.' - +LCB = '{' - +RCB = '}' - +LBRAC = '[' - +RBRAC = ']' - +LPAREN = '(' - +RPAREN = ')' - +DQUOTE = '"' - +SQUOTE = "'" - + +%% +; + +oop proto_symbol, name_symbol; + +oop integer_proto, add_proto; +oop integer_symbol, add_symbol; + +oop value_symbol, lhs_symbol, rhs_symbol; + +oop newObject(oop proto) +{ + oop map = makeMap(); + map_set(map, proto_symbol, proto); + return map; +} + +void printObjectName(oop object) +{ + assert(is(Map, object)); + oop name = map_get(object, name_symbol); + if (name != null) { + println(name); + return; + } + + oop proto = map_get(object, proto_symbol); + if (proto != null) { + printObjectName(proto); + } else { + fprintf(stderr, "\nThis map has no name\n"); + } +} + +// why use a macro instead of a regular function? +oop newInteger(int value) +{ + oop integer = newObject(integer_proto); + map_set(integer, value_symbol, makeInteger(value)); + return integer; +} + +oop newAdd(oop lhs, oop rhs) +{ + oop add = newObject(add_proto); + map_set(add, lhs_symbol, lhs); + map_set(add, rhs_symbol, rhs); + return add; +} + +// this always creates the key in "object" +oop newMember(oop object, oop key, oop value) +{ + map_set(object, key, value); + return value; +} + +// this follows the __proto__ chain until it finds the key, if it fails it behaves like newMember +oop setMember(oop object, oop key, oop value) +{ + /* + assert(is(Map, object)); + oop proto = object; + + for (;;) { + ssize_t pos = map_search(object, key); + if (pos > 0) { + map_in + } + proto = map_get(object, proto_symbol); + if (proto == null) { + return newMember(object, key, value); + } + } + while (map_search(proto, key) < 0) { + } + + do { + pos = map_search(object, key); + oop object = map_get(object, proto_symbol); + if (object == null) { + newMember() + } + } while (pos < 0); + */ +} + + +int main(int argc, char **argv) +{ + symbol_table = makeMap(); + globals = makeMap(); + + // Symbols + proto_symbol = intern("__proto__"); + name_symbol = intern("__name__"); + value_symbol = intern("value"); + lhs_symbol = intern("lhs"); + rhs_symbol = intern("rhs"); + + // Integer + integer_symbol = intern("Integer"); + integer_proto = makeMap(); + map_set(integer_proto, name_symbol, integer_symbol); + + // Addition + add_symbol = intern("Add"); + add_proto = makeMap(); + map_set(add_proto, name_symbol, add_symbol); + + + + oop myInteger = newInteger(32); + println(myInteger); + oop myAddition = newAdd(myInteger, myInteger); + println(myAddition); + + printObjectName(myAddition); + printObjectName(myInteger); + + while (yyparse()) { + println(yylval); + } + + return 0; + + (void)yyAccept; +} diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..3af0c3a --- /dev/null +++ b/test.txt @@ -0,0 +1,5 @@ +s = {} +s.pizza = "ok" +s.pizza +s.inside = {} +s.inside.pizza = "no" \ No newline at end of file diff --git a/tests/test3.txt b/tests/test3.txt deleted file mode 100644 index 1be8de3..0000000 --- a/tests/test3.txt +++ /dev/null @@ -1,6 +0,0 @@ -s = {} -chaussure = "parfois" -#manger -manger -s.pizza = "ok" -s \ No newline at end of file