end
end
- def linenum(tok = nil)
- @text[0..(tok.pos || @data.pos)].count("\n") + 1
+ def linenum(pos = nil)
+ @text[0..(pos || @data.pos)].count("\n") + 1
end
end
LVLNAMES = LEVELS.keys
RULES = {
-# "." => { prefix: nil, infix: :ufcs_call, level: :call },
- "(" => { prefix: :grouping, infix: :func_call, level: :call },
- "+" => { prefix: :unary, infix: :binary, level: :term },
- "-" => { prefix: :unary, infix: :binary, level: :term },
- "*" => { prefix: nil, infix: :binary, level: :factor },
- "/" => { prefix: nil, infix: :binary, level: :factor },
- "=" => { prefix: nil, infix: :assign, level: :assign },
- :let => { prefix: :definition, infix: nil, level: :none },
- :fun => { prefix: :function, infix: nil, level: :none },
- :if => { prefix: :if_expr, infix: nil, level: :none },
- :ident => { prefix: :variable, infix: nil, level: :none },
- "[" => { prefix: :constant, infix: :subscript, level: :call },
- "{" => { prefix: :constant, infix: nil, level: :none },
- :nil => { prefix: :constant, infix: nil, level: :none },
- :bool => { prefix: :constant, infix: nil, level: :none },
- :num => { prefix: :constant, infix: nil, level: :none },
- :string => { prefix: :constant, infix: nil, level: :none },
- :char => { prefix: :constant, infix: nil, level: :none },
- :byte => { prefix: :constant, infix: nil, level: :none },
+ "(" => { prefix: :grouping, infix: :func_call, level: :call },
+ "+" => { prefix: :unary, infix: :binary, level: :term },
+ "-" => { prefix: :unary, infix: :binary, level: :term },
+ "*" => { prefix: nil, infix: :binary, level: :factor },
+ "/" => { prefix: nil, infix: :binary, level: :factor },
+ "=" => { prefix: nil, infix: :definition, level: :assign },
+ :fun => { prefix: :function, infix: nil, level: :none },
+ :if => { prefix: :if_expr, infix: nil, level: :none },
+ :ident => { prefix: :variable, infix: nil, level: :none },
+ "[" => { prefix: :constant, infix: :subscript, level: :call },
+ "{" => { prefix: :constant, infix: nil, level: :none },
+ :nil => { prefix: :constant, infix: nil, level: :none },
+ :bool => { prefix: :constant, infix: nil, level: :none },
+ :num => { prefix: :constant, infix: nil, level: :none },
+ :string => { prefix: :constant, infix: nil, level: :none },
+ :char => { prefix: :constant, infix: nil, level: :none },
+ :byte => { prefix: :constant, infix: nil, level: :none },
}
Val = Struct.new(:loc, :type, :value)
@next = nil
end
+ #######################################
+ # Parsing Rules
+ #######################################
def toplevel()
- defs = []
+ defs = {}
exprs = []
while !matches(:eof)
expr = expression()
if expr.is_a? Def
- pp expr
+ error("global symbol '#{expr.name}' multiply defined") if defs[expr.name]
+ defs[expr.name] = expr.loc
exprs << Call.new(expr.loc, :set!, [expr.name, expr.value])
else
exprs << expr;
end
end
- exprs
+ [defs, exprs]
end
- #######################################
- # Expression Parsing
- #######################################
def expression()
parseLevel(:assign)
end
LVLNAMES[index + 1]
end
- def assign(left)
- Call.new(location(), :set!, [left, expression()])
- end
-
def variable()
@prev.text.to_sym
end
- def definition()
+ def definition(name)
loc = location()
- name = expect(:ident).text.to_sym
- expr = nil
- if (matches("("))
- expr = function()
- else
- expect("=")
- expr = expression()
- end
+ expr = expression()
Def.new(loc, name, expr)
end
#######################################
# Parsing Primitives
#######################################
- def error(str)
- puts "#{@lex.file}:#{@lex.linenum(@next || @prev)}: #{str}"
+ def error(str, loc = nil)
+ file, pos = (loc ? loc : [@lex.file, (@next || @prev).pos])
+ puts "#{file}:#{@lex.linenum(pos)}: #{str}"
exit 1
end
end
end
-
-module Emit
- def self.expr(e)
- if (e.is_a? Parser::Call)
- Emit.call(e)
- elsif (e.is_a? Symbol)
- "#{e}"
- elsif (e.is_a? String)
- "MKSTRING(#{e})"
- elsif (e.is_a? Float)
- "MKFLOAT(#{e})"
- else
- puts e
+class CodeGenerator
+ def initialize(defs, exprs)
+ @syms = Symtable.new
+ @funcs = { toplevel: { freevars: [], code: StringIO.new } }
+ @protos = StringIO.new
+ @protos.print "Value "
+ defs.each do |k,v|
+ @syms[k] = :toplevel
+ @protos.print "#{k}, "
end
+ @protos.puts "_;"
+ exprs.each {|e| emit(e) }
end
- def self.string(e)
- "MKSTR(#{e})"
+ def mkvar()
+ @id = 0 if @id.nil?
+ @id++
+ "_tmp#{@id}"
end
- def self.call(e)
- if e.func == :set! then
- "#{e.args[0]} = #{Emit.expr(e.args[1])};"
- elsif %w[+ - * /].include?(e.func)
- "#{Emit.expr(e.args[0])} #{e.func} #{Emit.expr(e.args[1])}"
- else
- Emit.calln(e)
+ def emitop(op, left, right = nil)
+ @body << [mkvar, op, left, right]
+ @body.last
+ end
+
+ def func_start(name, args = [])
+ args.each {|a| @syms[a] = :arg }
+ @syms[name] = :func
+ @syms.scope_start
+ @funcs[name.to_sym] = { freevars: [], code: StringIO.new }
+ end
+
+ def func_stop()
+ @syms.scope_stop
+ end
+
+ def dump
+ pp @syms
+ puts @protos.string
+ end
+
+ def emit(e)
+ if e.is_a? Parser::Val
+ emit_val(e)
+ elsif e.is_a? Parser::Def
+ puts "Def"
+ elsif e.is_a? Parser::Call
+ puts "Call"
+ elsif e.is_a? Parser::IfExpr
+ puts "IfExpr"
+ elsif e.is_a? Parser::Func
+ puts "Func"
end
end
- def self.calln(e)
- len = e.args.length
- args = e.args.map{|a| Emit.expr(a) }.join(", ")
- if len <= 8
- "CALL#{len}(#{e.func}, #{args});"
- else
- "CALLN(#{e.func}, #{len}, #{args});"
+ def emit_val(e)
+ case e.type
+ when :nil
+ puts "NULL"
+ when :bool
+ puts e.value
+ when :num
+ puts e.value
+ when :string
+ puts e.value
end
end
end
-
parse = Parser.new("dyn.src")
-exprs = parse.toplevel
-pp exprs
+defs, exprs = parse.toplevel
+
+# Print the definition prototypes
+print "Value "
+defs.each {|k,v| print "#{k.to_s}, " }
+puts "_;"
+
+puts exprs
+
+#puts exprs
+#gen = CodeGenerator.new(defs, exprs)
+#gen.dump