# flags
INCS = -Isource/
CPPFLAGS = -D_XOPEN_SOURCE=700
-CFLAGS += ${INCS} ${CPPFLAGS}
+CFLAGS += ${INCS} ${CPPFLAGS} -g
LDFLAGS += ${LIBS}
#------------------------------------------------------------------------------
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);
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;
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;
+}
}
}
+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
case AST_INT: return "T_INT";
case AST_FLOAT: return "T_FLOAT";
case AST_BOOL: return "T_BOOL";
+ case AST_TEMP: return "$";
default: return "???";
}
}
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;
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:
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);
/* 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
*****************************************************************************/
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
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
def ccode(input)
cli(['-Asrc'], input)
end
+
+def anf(input)
+ ast(input, "anf")
+end
+