From: Michael D. Lowis Date: Mon, 25 May 2020 03:19:03 +0000 (-0400) Subject: tweaked syntax to get rid of let forms in favor of = for definitions X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=76bec1fb8aa4cb385dc740fd05f33441e0799d96;p=proto%2Fsclpl-rb.git tweaked syntax to get rid of let forms in favor of = for definitions --- diff --git a/dyn.rb b/dyn.rb index b94d519..beecb49 100755 --- a/dyn.rb +++ b/dyn.rb @@ -81,8 +81,8 @@ class Lexer 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 @@ -105,25 +105,23 @@ class Parser 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) @@ -138,24 +136,25 @@ class Parser @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 @@ -193,24 +192,13 @@ class Parser 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 @@ -315,8 +303,9 @@ class Parser ####################################### # 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 @@ -360,48 +349,85 @@ class Parser 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 diff --git a/dyn.src b/dyn.src index 4b596af..e91d4d0 100644 --- a/dyn.src +++ b/dyn.src @@ -1,35 +1,32 @@ # constants -[1,2,3] -{ "foo": 123 } nil true false 123 123.0 "foo" - -# operators -let a = (456 + 1) -let a = (456 - 1) -let a = (456 * 1) -let a = (456 - 1) -let a = (-1) -let a = (+1) - -# variables -let foo = 123 -foo = 42 - -# conditionals -if (1) - 2 -else - 3 -end - -# functions and application -println("foo!") -print(1,2,3,4,5,6,7,8,9) -let foo = fun(a) +a = 1 +#[1,2,3] +#{ "foo": 123, 42: 24 } +# +## operators +#a = (456 + 1) +#b = (456 - 1) +#c = (456 * 1) +#d = (456 - 1) +#e = (-1) +#f = (+1) +# +## conditionals +#if (1) +# 2 +#else +# 3 +#end +# +## functions and application +#println("foo!") +#print(1,2,3,4,5,6,7,8,9) +foo1 = fun(a) println("hi!") end diff --git a/runtime b/runtime new file mode 100644 index 0000000..5a44562 --- /dev/null +++ b/runtime @@ -0,0 +1,195 @@ +Generic: + apply + map + foreach + +List: + list? + list + list-length + list-ref + list-append + list-map + list-foreach + +Vector: + vector? + vector + make-vector + vector-length + vector-ref + vector-append + vector-map + vector-foreach + +String: + string? + string + make-string + string-length + string-ref + string-append + string-map + string-foreach + +Map: + +Type conversion + vector->list + list->vector + number->string + string->number + symbol->string + string->symbol + char->integer + integer->char + string->list + list->string + + + + + pair? + cons + car + cdr + set-car! + set-cdr! + null? + append + reverse + list-tail + list-ref + memq. memv. member + assq + assv + assoc + list->vector + vector->list + list->string + string->list + vector->list + list->vector + string=? + string-ci=? + substring + string->list + list->string + string-copy + + + + + + + + + +Equivalence predicates + eq? + eqv? + equal? + string=? + string-ci=? + char=? + char-ci=? + + +Strings + +Characters + char? + char=? + char-ci=? + char? char-ci>? + char>=? char-ci>=? + char-alphabetic? + char-numeric? + char-whitespace? + char-upper-case? + char-lower-case? + char->integer + integer->char + char-upcase + char-downcase + +Vectors + +Symbols + symbol->string + string->symbol + symbol? + +Pairs and lists + pair? + cons + car + cdr + set-car! + set-cdr! + null? + list? + list + length + append + reverse + list-tail + list-ref + memq. memv. member + assq + assv + assoc + list->vector + vector->list + list->string + string->list + +Identity predicates + boolean? + pair? + symbol? + number? + char? + string? + vector? + port? + procedure? + +Continuations + call-with-current-continuation (call/cc) + values + call-with-values + dynamic-wind + +Environments + eval + scheme-report-environment + null-environment + interaction-environment (optional) + +Input/output + display + newline + read + write + read-char + write-char + peek-char + char-ready? + eof-object? open-input-file + open-output-file + close-input-port + close-output-port + input-port? + output-port? + current-input-port + current-output-port + call-with-input-file + call-with-output-file + with-input-from-file(optional) + with-output-to-file(optional) + +Booleans + boolean? not \ No newline at end of file