From: Michael D. Lowis Date: Mon, 21 May 2018 02:57:07 +0000 (-0400) Subject: attempted handling token parsing with a single token struct instead of heap allocatin... X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=e3da0e43d98a97bf62ebc88574edd6726a0c4bea;p=proto%2Fsclpl.git attempted handling token parsing with a single token struct instead of heap allocating each one --- diff --git a/Makefile b/Makefile index 1924618..3384587 100644 --- a/Makefile +++ b/Makefile @@ -4,13 +4,13 @@ # Update these variables according to your requirements. # tools -CC = c99 +CC = cc LD = ${CC} # completed flags INCS = -Isource/ CPPFLAGS = -CFLAGS += ${INCS} ${CPPFLAGS} +CFLAGS += -O0 -g ${INCS} ${CPPFLAGS} LDFLAGS += ${LIBS} ARFLAGS = rcs diff --git a/source/main.c b/source/main.c index 534ebd2..18b7d1d 100644 --- a/source/main.c +++ b/source/main.c @@ -1,7 +1,7 @@ #include char* ARGV0; -char* Artifact = "bin"; +char* Artifact = "ast"; /* Driver Modes *****************************************************************************/ diff --git a/source/parser.c b/source/parser.c index bb86726..a461186 100644 --- a/source/parser.c +++ b/source/parser.c @@ -8,20 +8,18 @@ /* Private Declarations *****************************************************************************/ -// Sentinel EOF Token -Tok tok_eof = { NULL, 0, 0, T_END_FILE, {0} }; - // Grammar Routines -static AST* require(Parser* p); +static AST* const_definition(Parser* p); +static AST* const_expression(Parser* p); static AST* definition(Parser* p); static AST* expression(Parser* p); -static AST* if_stmnt(Parser* p); static AST* function(Parser* p); +static void type_annotation(Parser* p); static AST* literal(Parser* p); static AST* expr_block(Parser* p); +static AST* if_stmnt(Parser* p); static AST* token_to_tree(Tok* tok); static AST* func_app(Parser* p, AST* fn); -static void type_annotation(Parser* p); // Parsing Routines static void fetch(Parser* parser); @@ -35,41 +33,59 @@ static Tok* expect(Parser* parser, TokType type); /* Grammar Definition *****************************************************************************/ -AST* toplevel(Parser* p) -{ +AST* toplevel(Parser* p) { AST* ret = NULL; if (!match(p, T_END_FILE)) { if (accept(p, T_DEF)) - ret = definition(p); + ret = const_definition(p); else error(p, "only definitions are allowed at the toplevel"); } return ret; } -static AST* definition(Parser* p) -{ +static AST* const_definition(Parser* p) { AST* expr; Tok* id = expect(p, T_ID); if (peek(p)->type == T_LPAR) { expr = function(p); } else { type_annotation(p); - expr = expression(p); + expr = const_expression(p); expect(p, T_END); } return Def(id, expr); } -static AST* require(Parser* p) -{ - AST* ast = Require(expect(p, T_STRING)); - expect(p, T_END); - return ast; +static AST* const_expression(Parser* p) { + AST* expr = NULL; + if (accept(p, T_LPAR)) { + expr = const_expression(p); + expect(p, T_RPAR); + } else if (accept(p, T_FN)) { + expr = function(p); + } else if (match(p, T_ID)) { + expr = Ident(expect(p,T_ID)); + } else { + expr = literal(p); + } + return expr; } -static AST* expression(Parser* p) -{ +static AST* definition(Parser* p) { + AST* expr; + Tok* id = expect(p, T_ID); + if (peek(p)->type == T_LPAR) { + expr = function(p); + } else { + type_annotation(p); + expr = expression(p); + expect(p, T_END); + } + return Def(id, expr); +} + +static AST* expression(Parser* p) { AST* expr = NULL; if (accept(p, T_LPAR)) { expr = expression(p); @@ -89,20 +105,7 @@ static AST* expression(Parser* p) return expr; } -static AST* if_stmnt(Parser* p) -{ - AST* ifexpr = IfExpr(); - ifexpr_set_cond( ifexpr, expression(p) ); - accept(p, T_THEN); - ifexpr_set_then( ifexpr, expr_block(p) ); - if (accept(p, T_ELSE)) - ifexpr_set_else( ifexpr, expr_block(p) ); - expect(p,T_END); - return ifexpr; -} - -static AST* function(Parser* p) -{ +static AST* function(Parser* p) { AST* func = Func(); expect(p, T_LPAR); while(peek(p)->type != T_RPAR) { @@ -118,8 +121,19 @@ static AST* function(Parser* p) return func; } -static AST* literal(Parser* p) -{ +static void type_annotation(Parser* p) { + expect(p, T_ID); + /* array type */ + if (accept(p,T_LBRACK)) { + accept(p, T_INT); + expect(p, T_RBRACK); + /* reference type */ + } else if (accept(p, T_AMP)) { + // TODO: implement reference types + } +} + +static AST* literal(Parser* p) { AST* ret = NULL; Tok* tok = peek(p); switch (tok->type) { @@ -136,8 +150,7 @@ static AST* literal(Parser* p) return ret; } -static AST* expr_block(Parser* p) -{ +static AST* expr_block(Parser* p) { AST* block = NULL; vec_t exprs; vec_init(&exprs); @@ -175,8 +188,18 @@ static AST* token_to_tree(Tok* tok) } } -static AST* func_app(Parser* p, AST* fn) -{ +static AST* if_stmnt(Parser* p) { + AST* ifexpr = IfExpr(); + ifexpr_set_cond( ifexpr, expression(p) ); + accept(p, T_THEN); + ifexpr_set_then( ifexpr, expr_block(p) ); + if (accept(p, T_ELSE)) + ifexpr_set_else( ifexpr, expr_block(p) ); + expect(p,T_END); + return ifexpr; +} + +static AST* func_app(Parser* p, AST* fn) { AST* app = FnApp(fn); expect(p,T_LPAR); while (peek(p)->type != T_RPAR) { @@ -188,19 +211,6 @@ static AST* func_app(Parser* p, AST* fn) return app; } -static void type_annotation(Parser* p) -{ - expect(p, T_ID); - /* array type */ - if (accept(p,T_LBRACK)) { - accept(p, T_INT); - expect(p, T_RBRACK); - /* reference type */ - } else if (accept(p, T_AMP)) { - - } -} - /* Parsing Routines *****************************************************************************/ Parser* parser_new(char* prompt, FILE* input) @@ -217,11 +227,11 @@ static void fetch(Parser* parser) gettoken(parser, &(parser->tok)); } -static Tok* peek(Parser* parser) +static Tok* peek(Parser* p) { - if (T_NONE == parser->tok.type) - fetch(parser); - return &(parser->tok); + if (T_NONE == p->tok.type) + gettoken(p, &(p->tok)); + return &(p->tok); } static bool parser_eof(Parser* parser) @@ -265,4 +275,3 @@ static Tok* expect(Parser* parser, TokType type) error(parser, "Unexpected token"); return tok; } - diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index 7e6f348..0452253 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -1,81 +1,55 @@ require 'open3' describe "sclpl grammar" do - context "requires" do - it "should parse a require statement" do - expect(ast('require "foo";')).to eq([ ['require', '"foo"'] ]) - end - - it "should parse a require statement using end keyword" do - expect(ast('require "foo" end')).to eq([ ['require', '"foo"'] ]) - end - - it "should error on missing semicolon" do - expect{ast('require "foo"')}.to raise_error /Error/ - end - - it "should error on missing filename" do - expect{ast('require ;')}.to raise_error /Error/ - end - - it "should error on invalid filename type" do - expect{ast('require 123;')}.to raise_error /Error/ - end - - it "should error on too many parameters" do - expect{ast('require foo bar;')}.to raise_error /Error/ - end - end - - context "definitions" do - it "should parse a value definition with type annotation" do - expect(ast('def foo int 123;')).to eq([ ['def', 'foo', 'T_INT:123'] ]) - end - - it "should parse a function definition with return type annotation" do - expect(ast('def foo() int 123;')).to eq([ - ['def', 'foo', ['fn', [], - ["let", ["$:0", "T_INT:123"], "$:0"]]] ]) - end - - it "should error on a function definition with missing return type" do - pending("TODO: fix the error message here") - expect(ast('def foo() 123;')).to raise_error /Error/ - end - - it "should parse a function definition with multiple expressions in the body" do - expect(ast('def foo() int 123 321;')).to eq([ - ['def', 'foo', ['fn', [], - ["let", ["$:0", "T_INT:123"], - ["let", ["$:1", "T_INT:321"], "$:1"]]]]]) - end - - it "should parse a function definition with one definition and expression" do - expect(ast('def foo() int def bar int 123; add(bar,321);')).to eq([ - ['def', 'foo', ['fn', [], - ["let", ["T_ID:bar", "T_INT:123"], - ["let", ["$:0", ["T_ID:add", "T_ID:bar", "T_INT:321"]], "$:0"]]]]]) - end - - it "should parse a function definition with one argument" do - expect(ast('def foo(a int) int 123;')).to eq([ - ['def', 'foo', ['fn', ['T_ID:a'], - ["let", ["$:0", "T_INT:123"], "$:0"]]]]) - end - - it "should parse a function definition with two arguments" do - expect(ast('def foo(a int, b int) int 123;')).to eq([ - ['def', 'foo', ['fn', ['T_ID:a', 'T_ID:b'], - ["let", ["$:0", "T_INT:123"], "$:0"]]]]) - end - - it "should parse a function definition with three arguments" do - expect(ast('def foo(a int, b int, c int) int 123;')).to eq([ - ['def', 'foo', ['fn', ['T_ID:a', 'T_ID:b', 'T_ID:c'], - ["let", ["$:0", "T_INT:123"], "$:0"]]]]) - end - end - +# context "definitions" do +# it "should parse a value definition with type annotation" do +# expect(ast('def foo int 123;')).to eq([ ['def', 'foo', 'T_INT:123'] ]) +# end +# +# it "should parse a function definition with return type annotation" do +# expect(ast('def foo() int 123;')).to eq([ +# ['def', 'foo', ['fn', [], +# ["let", ["$:0", "T_INT:123"], "$:0"]]] ]) +# end +# +# it "should error on a function definition with missing return type" do +# pending("TODO: fix the error message here") +# expect(ast('def foo() 123;')).to raise_error /Error/ +# end +# +# it "should parse a function definition with multiple expressions in the body" do +# expect(ast('def foo() int 123 321;')).to eq([ +# ['def', 'foo', ['fn', [], +# ["let", ["$:0", "T_INT:123"], +# ["let", ["$:1", "T_INT:321"], "$:1"]]]]]) +# end +# +# it "should parse a function definition with one definition and expression" do +# expect(ast('def foo() int def bar int 123; add(bar,321);')).to eq([ +# ['def', 'foo', ['fn', [], +# ["let", ["T_ID:bar", "T_INT:123"], +# ["let", ["$:0", ["T_ID:add", "T_ID:bar", "T_INT:321"]], "$:0"]]]]]) +# end +# +# it "should parse a function definition with one argument" do +# expect(ast('def foo(a int) int 123;')).to eq([ +# ['def', 'foo', ['fn', ['T_ID:a'], +# ["let", ["$:0", "T_INT:123"], "$:0"]]]]) +# end +# +# it "should parse a function definition with two arguments" do +# expect(ast('def foo(a int, b int) int 123;')).to eq([ +# ['def', 'foo', ['fn', ['T_ID:a', 'T_ID:b'], +# ["let", ["$:0", "T_INT:123"], "$:0"]]]]) +# end +# +# it "should parse a function definition with three arguments" do +# expect(ast('def foo(a int, b int, c int) int 123;')).to eq([ +# ['def', 'foo', ['fn', ['T_ID:a', 'T_ID:b', 'T_ID:c'], +# ["let", ["$:0", "T_INT:123"], "$:0"]]]]) +# end +# end +# # context "literals" do # it "should parse a string" do # expect(ast('"foo"')).to eq(['T_STRING:"foo"'])