From: Michael D. Lowis Date: Fri, 18 Dec 2015 02:28:23 +0000 (-0500) Subject: Started implementing the anf conversion phase X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=4f45eaa19741839a2d2190d4abbf6a46289c2cd8;p=proto%2Fsclpl.git Started implementing the anf conversion phase --- diff --git a/Makefile b/Makefile index c924ccb..654a84d 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ LD = ${CC} # flags INCS = -Isource/ CPPFLAGS = -D_XOPEN_SOURCE=700 -CFLAGS += ${INCS} ${CPPFLAGS} +CFLAGS += ${INCS} ${CPPFLAGS} -g LDFLAGS += ${LIBS} #------------------------------------------------------------------------------ diff --git a/source/ast.c b/source/ast.c index 7185904..e545329 100644 --- a/source/ast.c +++ b/source/ast.c @@ -113,6 +113,13 @@ intptr_t integer_value(AST* val) return val->value.integer; } +intptr_t temp_value(AST* val) +{ + assert(val != NULL); + assert(val->type == AST_TEMP); + return val->value.integer; +} + AST* Float(Tok* val) { AST* node = ast(AST_FLOAT); @@ -284,6 +291,13 @@ AST* FnApp(AST* fnapp) return node; } +void fnapp_set_fn(AST* fnapp, AST* fn) +{ + AST* old = fnapp->value.fnapp.fn; + fnapp->value.fnapp.fn = (AST*)gc_addref(fn); + gc_delref(old); +} + AST* fnapp_fn(AST* fnapp) { return fnapp->value.fnapp.fn; @@ -307,3 +321,26 @@ AST* Let(AST* temp, AST* val, AST* body) node->value.let.body = (AST*)gc_addref(body); return node; } + +AST* let_var(AST* let) +{ + return let->value.let.temp; +} + +AST* let_val(AST* let) +{ + return let->value.let.value; +} + +AST* let_body(AST* let) +{ + return let->value.let.body; +} + +AST* TempVar(void) +{ + static intptr_t val = 0; + AST* node = ast(AST_TEMP); + node->value.integer = val++; + return node; +} diff --git a/source/main.c b/source/main.c index de5700c..2d225cc 100644 --- a/source/main.c +++ b/source/main.c @@ -21,9 +21,24 @@ bool isatomic(AST* tree) } } +AST* normalize_fnapp(AST* tree) +{ + AST* fn = fnapp_fn(tree); + if (!isatomic(fn)) { + AST* temp = TempVar(); + fnapp_set_fn(tree, temp); + return Let(temp, fn, tree); + } else { + return tree; + } +} + AST* normalize(AST* tree) { - return tree; + if (tree->type == AST_FNAPP) + return normalize_fnapp(tree); + else + return tree; } /* Driver Modes diff --git a/source/pprint.c b/source/pprint.c index 2758203..0cc839d 100644 --- a/source/pprint.c +++ b/source/pprint.c @@ -93,6 +93,7 @@ static const char* tree_type_to_string(ASTType type) { case AST_INT: return "T_INT"; case AST_FLOAT: return "T_FLOAT"; case AST_BOOL: return "T_BOOL"; + case AST_TEMP: return "$"; default: return "???"; } } @@ -107,6 +108,7 @@ static void pprint_literal(FILE* file, AST* tree, int depth) case AST_CHAR: printf("%c", char_value(tree)); break; case AST_INT: printf("%ld", integer_value(tree)); break; case AST_FLOAT: printf("%lf", float_value(tree)); break; + case AST_TEMP: printf("%ld", temp_value(tree)); break; case AST_BOOL: printf("%s", bool_value(tree) ? "true" : "false"); break; @@ -174,7 +176,13 @@ void pprint_tree(FILE* file, AST* tree, int depth) break; case AST_LET: - printf("(let)"); + printf("(let ("); + pprint_tree(file, let_var(tree), depth); + printf(" "); + pprint_tree(file, let_val(tree), depth); + printf(") "); + pprint_tree(file, let_body(tree), depth); + printf(")"); break; default: diff --git a/source/sclpl.h b/source/sclpl.h index 92acc64..274c9fe 100644 --- a/source/sclpl.h +++ b/source/sclpl.h @@ -149,6 +149,10 @@ bool bool_value(AST* val); AST* Ident(Tok* val); char* ident_value(AST* val); +/* Temp Variable */ +AST* TempVar(void); +intptr_t temp_value(AST* val); + /* Require */ AST* Require(Tok* name); char* require_name(AST* req); @@ -183,11 +187,15 @@ void func_set_body(AST* func, AST* body); /* Function Application */ AST* FnApp(AST* fn); AST* fnapp_fn(AST* fnapp); +void fnapp_set_fn(AST* fnapp, AST* fn); vec_t* fnapp_args(AST* fnapp); void fnapp_add_arg(AST* func, AST* arg); /* Let Expression */ AST* Let(AST* temp, AST* val, AST* body); +AST* let_var(AST* let); +AST* let_val(AST* let); +AST* let_body(AST* let); /* Lexer and Parser Types *****************************************************************************/ diff --git a/spec/anf_spec.rb b/spec/anf_spec.rb index 0f70771..229d8c6 100644 --- a/spec/anf_spec.rb +++ b/spec/anf_spec.rb @@ -3,27 +3,41 @@ require 'open3' describe "sclpl a-normal form" do context "literals" do it "strings should remain untouched" do - expect(ast('"foo"')).to eq(['T_STRING:"foo"']) + expect(anf('"foo"')).to eq(['T_STRING:"foo"']) end it "characters should remain untouched" do - expect(ast('\\c')).to eq(['T_CHAR:c']) + expect(anf('\\c')).to eq(['T_CHAR:c']) end it "integers should remain untouched" do - expect(ast('123')).to eq(['T_INT:123']) + expect(anf('123')).to eq(['T_INT:123']) end it "floats should remain untouched" do - expect(ast('123.0')).to eq(['T_FLOAT:123.000000']) + expect(anf('123.0')).to eq(['T_FLOAT:123.000000']) end it "booleans should remain untouched" do - expect(ast('true')).to eq(['T_BOOL:true']) + expect(anf('true')).to eq(['T_BOOL:true']) end it "ids should remain untouched" do - expect(ast('foo')).to eq(['T_ID:foo']) + expect(anf('foo')).to eq(['T_ID:foo']) + end + end + + context "function applications" do + it "should leave an application with no args alone" do + expect(anf('foo()')).to eq([['T_ID:foo']]) + end + + it "should leave an application with one arg alone" do + expect(anf('foo(a)')).to eq([['T_ID:foo', 'T_ID:a']]) + end + + it "should normalize an application with a complex function" do + expect(anf('(foo())()')).to eq([['let', ['$:0', ['T_ID:foo']], ['$:0']]]) end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b931a73..142c88f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -29,8 +29,8 @@ def re_structure( token_array, offset = 0 ) return [offset, struct] end -def ast(input) - out = cli(['-Aast'], input) +def ast(input, pass="ast") + out = cli(["-A#{pass}"], input) # Prep the parens for reading out.gsub!(/([()])|tree/,' \1 ') # Replace string literals so we can tokenize on spaces @@ -55,3 +55,8 @@ end def ccode(input) cli(['-Asrc'], input) end + +def anf(input) + ast(input, "anf") +end +