From 9f52e4ad1191261b1911da68e6ea8b7632a78a44 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Mon, 13 Nov 2023 22:01:20 -0500 Subject: [PATCH] added func calls and paren grouping. argument access is broken and needs some carfule thought --- cerise.m | 7 +- cerise.rb | 195 +++++++++++++++++++++++------------------------------- 2 files changed, 90 insertions(+), 112 deletions(-) diff --git a/cerise.m b/cerise.m index 9c3468f..8de6003 100644 --- a/cerise.m +++ b/cerise.m @@ -1,4 +1,9 @@ +sum(a,b) +{ + return a+b +} + main() { - return 42 * 2 + return sum(1+1,2) } diff --git a/cerise.rb b/cerise.rb index 513eb6b..8a34205 100755 --- a/cerise.rb +++ b/cerise.rb @@ -107,11 +107,13 @@ class SymTable < Hash not (self[key] || {})[:type].nil? end - def add_sym(name, loc, kind, type = nil) + def add_sym(name, loc, kind, scope = :local, type = nil, value = nil) self[name] = { loc: loc, kind: kind, - type: type + scope: scope, + type: type, + value: nil } end @@ -128,74 +130,6 @@ class SymTable < Hash nil end end - - def depth - count = 0 - env = self - while env.class != Hash - count += 1 - env = env.parent - end - count - end - -# def local(key) -# method(:[]).super_method.call(key) -# end -# -# def defined_ever?(key) -# (not (self[key] || {})[:type].nil?) -# end -# -# def defined_locally?(key) -# (not (local(key) || {})[:type].nil?) -# end -# -# def block_local?(key) -# (not local(key).nil?) -# end -# -# def global?(key) -# if @parent.class == Hash -# block_local?(key) -# elsif block_local? key -# false -# else -# @parent.global? key -# end -# end -# -# def local?(key) -# if @parent.class == Hash -# false -# elsif @type == :func -# block_local? key -# else -# @parent.local? key -# end -# end -# -# def free?(key) -# (defined_ever? key) and (not local? key) and (not global? key) -# end -# -# def merge!(env) -# env.each {|k,v| self[k] = v } -# end -# -# def annotate(key, type) -# self[key] ||= {} -# self[key][:ann] = type -# end -# -# def annotation(key) -# (method(:[]).super_method.call(key) || {})[:ann] -# end -# -# def stack() -# parent = (@parent.is_a?(SymTable) ? @parent.stack : []) -# ([self] + parent).flatten -# end end module IR @@ -205,7 +139,7 @@ module IR Var = Struct.new(:loc, :type, :name) Def = Struct.new(:loc, :type, :name, :value) Op = Struct.new(:loc, :type, :op, :left, :right) - + Call = Struct.new(:loc, :type, :func, :args) # EnvRef = Struct.new(:loc, :type, :index) # Let = Struct.new(:loc, :type, :var, :expr, :body) @@ -536,17 +470,17 @@ end class Parser - attr_accessor :exprs +# attr_accessor :exprs attr_accessor :syms attr_accessor :defs def initialize(path = nil) @syms = SymTable.new - syms.add_sym(:void, 0, :type, :void) - syms.add_sym(:bool, 0, :type, :bool) - syms.add_sym(:int, 0, :type, :int) - syms.add_sym(:string, 0, :type, :string) - syms.add_sym(:float, 0, :type, :float) + syms.add_sym(:void, 0, :type, :builtin, :void) + syms.add_sym(:bool, 0, :type, :builtin, :bool) + syms.add_sym(:int, 0, :type, :builtin, :int) + syms.add_sym(:string, 0, :type, :builtin, :string) + syms.add_sym(:float, 0, :type, :builtin, :float) parse_file(path) end @@ -630,8 +564,29 @@ class Parser imports exports @defs = {} +# @syms = SymTable.new + while !matches(:eof) mod_def = toplevel_defintion() + +# kind = (case mod_def.value.class +# when IR::Const.class +# :const +# when IR::Var.class +# :var +# when IR::Func.class +# :func +# else +# raise "invalid toplevel definition #{mod_def.value.class}" +# end) +# @syms.add_sym( +# mod_def.name.name, +# 0, +# kind, +# :global, +# nil, +# mod_def.value) + @defs[mod_def.name.name] = mod_def end end @@ -706,7 +661,7 @@ class Parser def simple_expr() # Handle unary ops first - if matches_any(["+", "-"]) + if matches_any(["+", "-", :not]) op = consume() left = term() left = IR::Op.new(op.location, nil, op.text, left, nil) @@ -721,35 +676,6 @@ class Parser left = IR::Op.new(location, nil, op.text, left, right) end left -# 269 /* first term and +/- unary ops */ -# 270 if (matches_oneof(p, (int[]){'+', '-', 0})) -# 271 { -# 272 int op = consume(p); -# 273 SsaNode* operand = term(p); -# 274 check_num(p, operand); -# 275 expr = ssa_op(p, op, operand, NULL); -# 276 } -# 277 else -# 278 { -# 279 expr = term(p); -# 280 } -# 281 -# 282 /* optional second term and binary ops */ -# 283 while (matches_oneof(p, (int[]){'+', '-', OR, 0})) -# 284 { -# 285 int op = consume(p); -# 286 SsaNode* right = term(p); -# 287 if (op == OR) -# 288 { -# 289 check_bools(p, expr, right); -# 290 } -# 291 else -# 292 { -# 293 check_nums(p, expr, right); -# 294 } -# 295 expr = ssa_op(p, op, expr, right); -# 296 } - end def term() @@ -763,10 +689,32 @@ class Parser end def factor() - constant() + if accept("(") + expr = expression() + expect(")") + else + expr = const_or_ident() + end + + # Check for function call + if matches("(") + expr = func_call(expr) + end + expr + end + + def func_call(expr) + call = IR::Call.new(location, nil, expr, []) + expect("(") + while !matches(")") + call.args << expression() + expect(",") if !matches(")") + end + expect(")") + call end - def constant() + def const_or_ident() tok = consume() if tok.type == :bool IR::Const.new(tok.pos, :bool, tok.text == "true") @@ -778,6 +726,8 @@ class Parser IR::Const.new(tok.pos, :float, tok.text.to_f) elsif tok.type == :void IR::Const.new(tok.pos, :void, :void) + elsif tok.type == :ident + IR::Var.new(tok.pos, nil, tok.text.to_sym) else error("invalid constant") end @@ -792,6 +742,10 @@ module Codegen emit_const(v) elsif v.is_a? IR::Op then emit_binop(v) + elsif v.is_a? IR::Var then + emit_var(v) + elsif v.is_a? IR::Call then + emit_call(v) else raise "code emitting of #{v.class} not implemented" end @@ -826,14 +780,33 @@ module Codegen raise "not implemented" end end + + def self.emit_var(v) + puts " #{v.name}" + end + + def self.emit_call(v) + v.args.reverse.each do |arg| + emit(arg) + end + # TODO: handle args/locals/globals + if v.func.is_a? IR::Var + puts " call #{v.func.name}" + else + emit(v.func) + emit " callv" + end + end end $parser = Parser.new("cerise.m") +#pp $parser.syms +#pp $parser.defs $parser.defs.each do |name, val| - puts "func #{name.to_sym.inspect} do" + puts "func #{name.to_sym.inspect}, #{val.value.args.length} do" val.value.body.each do |stmnt| Codegen.emit(stmnt) end - puts "end" + puts "end\n\n" # puts val end -- 2.54.0