From: Michael D. Lowis Date: Fri, 17 Oct 2014 19:52:38 +0000 (-0400) Subject: Added spec for C code generator (still busted). Enabled optimization for the main... X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=61bd0fa6c93ac69b36b6fcdbdd95f5a9e45f46b5;p=proto%2Fsclpl.git Added spec for C code generator (still busted). Enabled optimization for the main build. Switched require syntax to use strings --- diff --git a/Rakefile b/Rakefile index 565caa5..3051900 100644 --- a/Rakefile +++ b/Rakefile @@ -18,6 +18,10 @@ base_env = BuildEnv.new(echo: :command) do |env| env["CPPPATH"] += ['modules/libopts/source'] + Dir['modules/libcds/source/**/'] end +main_env = base_env.clone do |env| + env["CFLAGS"] += ['-O3'] +end + test_env = base_env.clone do |env| env.build_dir('source','build/obj/test/source') env.build_dir('modules','build/obj/test/modules') @@ -64,16 +68,16 @@ task :build => [:clang, :sclpl] desc "Build the sclpl compiler and interpreter" task :sclpl => [:libcds, :libopts] do - base_env.Program('build/bin/sclpl', + main_env.Program('build/bin/sclpl', FileList['source/sclpl/*.c', 'build/lib/libopts.a', 'build/lib/libcds.a']) end task :libcds do - base_env.Library('build/lib/libcds.a', FileList['modules/libcds/source/**/*.c']) + main_env.Library('build/lib/libcds.a', FileList['modules/libcds/source/**/*.c']) end task :libopts do - base_env.Library('build/lib/libopts.a', FileList['modules/libopts/source/**/*.c']) + main_env.Library('build/lib/libopts.a', FileList['modules/libopts/source/**/*.c']) end #------------------------------------------------------------------------------ @@ -103,6 +107,6 @@ RSpec::Core::RakeTask.new(:spec) do |t,args| t.rspec_opts = ['--format', 'documentation'] test_env.Program('build/bin/sclpl-test', FileList['source/sclpl/*.c', 'build/lib/libopts.a', 'build/lib/libcds.a']) - base_env.process + main_env.process test_env.process end diff --git a/source/sclpl/codegen.c b/source/sclpl/codegen.c index 071a491..8bc9324 100644 --- a/source/sclpl/codegen.c +++ b/source/sclpl/codegen.c @@ -85,45 +85,7 @@ static void print_indent(int depth) { } static void emit_header(void) { - //puts("#include \n"); - printf( - "\n#include " - "\n" - "\ntypedef void* _Value;" - "\n" - "\n#define NIL ((_Value) 0)" - "\n#define apply(a,...) ((_Value)0)" - "\n#define IF(cnd) (cnd)?" - "\n#define ELSE :" - "\n" - "\n#define make(type, value) \\" - "\n make_ ## type (value)" - "\n" - "\nstatic _Value make_string(const char* val) {" - "\n return NIL;" - "\n}" - "\n" - "\nstatic _Value make_char(char val) {" - "\n return NIL;" - "\n}" - "\n" - "\nstatic _Value make_int(long int val) {" - "\n return NIL;" - "\n}" - "\n" - "\nstatic _Value make_float(double val) {" - "\n return NIL;" - "\n}" - "\n" - "\nstatic _Value make_bool(bool val) {" - "\n return NIL;" - "\n}" - "\n" - "\n#define make_fn(value) make_func((void*)(value))" - "\nstatic _Value make_func(void* val) {" - "\n return NIL;" - "\n}" - ); + puts("#include \n"); } static void emit_fn_signature(char* name, tree_t* fnval) { @@ -151,12 +113,12 @@ static void emit_expression(vec_t* fnlst, tree_t* p_tree, int depth) { if (p_tree->tag == ATOM) { lex_tok_t* tok = p_tree->ptr.tok; switch (tok->type) { - case T_STRING: printf("make(string,'%s')", ((char*)tok->value)); break; - case T_CHAR: printf("make(char,\\%c)", ((char)(int)tok->value)); break; - case T_INT: printf("make(int,%ld)", *((long int*)tok->value)); break; - case T_FLOAT: printf("make(float,%f)", *((double*)tok->value)); break; - case T_BOOL: printf("make(bool,%s)", ((int)tok->value)?"true":"false"); break; - case T_VAR: printf("%s", ((char*)tok->value)); break; + case T_STRING: printf("__string(%s)", ((char*)tok->value)); break; + case T_CHAR: printf("__char('%c')", ((char)(int)tok->value)); break; + case T_INT: printf("__int(%ld)", *((long int*)tok->value)); break; + case T_FLOAT: printf("__float(%f)", *((double*)tok->value)); break; + case T_BOOL: printf("__bool(%s)", ((int)tok->value)?"true":"false"); break; + case T_VAR: printf("%s", ((char*)tok->value)); break; } } else if (is_formtype(p_tree, "if")) { printf("IF ("); diff --git a/source/sclpl/grammar.c b/source/sclpl/grammar.c index 9083d2f..40b9502 100644 --- a/source/sclpl/grammar.c +++ b/source/sclpl/grammar.c @@ -28,7 +28,7 @@ tree_t* grammar_toplevel(parser_t* p_parser) void grammar_require(parser_t* p_parser) { size_t mark = parser_mark(p_parser); - parser_expect(p_parser, T_VAR); + parser_expect(p_parser, T_STRING); parser_expect(p_parser, T_END); parser_reduce(p_parser, mark); } diff --git a/spec/codegen_spec.rb b/spec/codegen_spec.rb new file mode 100644 index 0000000..d827bf0 --- /dev/null +++ b/spec/codegen_spec.rb @@ -0,0 +1,120 @@ +require 'spec_helper' + +InputSource = <<-eos +require "foo"; +def a 123; +def b +123; +def c -123; +def d 321.0; +def e +321.0; +def f -321.0; +def g 0b101; +def h 0o707; +def i 0d909; +def j 0hF0F; +def k 0hf0f; +def l \\space; +def m \\tab; +def n \\return; +def o \\newline; +def p \\vtab; +def q \\c; +def r ""; +def s " +"; +def t true; +def u false; +def v l; +def w() 0; +def x(a) 1; +def y(a,b) 2; +def z fn(a,b,c) 3;; +eos + +ExpectedCode = <<-eos +#include + +_Value a; +_Value b; +_Value c; +_Value d; +_Value e; +_Value f; +_Value g; +_Value h; +_Value i; +_Value j; +_Value k; +_Value l; +_Value m; +_Value n; +_Value o; +_Value p; +_Value q; +_Value r; +_Value s; +_Value t; +_Value u; +_Value v; +_Value w; +_Value x; +_Value y; + +static _Value fn0(); +static _Value fn1(_Value a); +static _Value fn2(_Value a, _Value b); + +static _Value fn0() { + return __int(0); +} + +static _Value fn1(_Value a) { + return __int(1); +} + +static _Value fn2(_Value a, _Value b) { + return __int(2); +} + +void toplevel(void) { + a = __int(123); + b = __int(123); + c = __int(-123); + d = __float(321.000000); + e = __float(321.000000); + f = __float(-321.000000); + g = __int(5); + h = __int(455); + i = __int(909); + j = __int(3855); + k = __int(3855); + l = __char(' '); + m = __char('\\t'); + n = __char('\\r'); + o = __char('\\n'); + p = __char('\\v'); + q = __char('c'); + r = __string(""); + s = __string("\\n"); + t = __bool(true); + u = __bool(false); + v = l; + w = __func(&fn0); + x = __func(&fn1); + y = __func(&fn2); +} + +int main(int argc, char** argv) { + (void)argc; + (void)argv; + toplevel(); + return 0; +} +eos + +describe "code generation" do + it "should generate some code" do + pending "busted" + expect(ccode(InputSource)).to eq ExpectedCode + end +end diff --git a/spec/lexer_spec.rb b/spec/lexer_spec.rb index 7857634..51a81b1 100644 --- a/spec/lexer_spec.rb +++ b/spec/lexer_spec.rb @@ -144,10 +144,14 @@ describe "lexer" do expect(lexer('"a"')).to eq ['T_STRING:"a"'] end - it "should recognize a string with one element" do + it "should recognize a string with two elements" do expect(lexer('"ab"')).to eq ['T_STRING:"ab"'] end + it "should recognize a string with a space" do + expect(lexer('"a b"')).to eq ['T_STRING:"a b"'] + end + it "should recognize a string that spans lines" do expect(lexer("\"a\nb\"")).to eq ["T_STRING:\"a\nb\""] end diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index dda0c4d..57016ca 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -3,15 +3,15 @@ require 'open3' describe "sclpl grammar" do context "requires" do it "should parse a require statement" do - expect(ast('require foo;')).to eq([ ['T_VAR:require', 'T_VAR:foo'] ]) + expect(ast('require "foo";')).to eq([ ['T_VAR:require', 'T_STRING:"foo"'] ]) end it "should parse a require statement using end keyword" do - expect(ast('require foo end')).to eq([ ['T_VAR:require', 'T_VAR:foo'] ]) + expect(ast('require "foo" end')).to eq([ ['T_VAR:require', 'T_STRING:"foo"'] ]) end it "should error on missing semicolon" do - expect{ast('require foo')}.to raise_error /Invalid Syntax/ + expect{ast('require "foo"')}.to raise_error /Invalid Syntax/ end it "should error on missing filename" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 521a463..ea3dcaa 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -49,3 +49,9 @@ def ast(input) expr end +def ccode(input) + out, err, status = Open3.capture3('./build/bin/sclpl-test', '--csource', :stdin_data => input) + raise err unless err == "" + raise "Parser command returned non-zero status" unless status.success? + out +end