From 6fd5660a72bdf2a9d97e03159c25528e6c92db5b Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Mon, 27 Jan 2020 16:54:27 -0500 Subject: [PATCH] added return statement and scaffolding for other statements --- compile.rb | 174 ++++++++++++++++++++++++++++++++++++++++++++-------- example.src | 11 ++-- 2 files changed, 156 insertions(+), 29 deletions(-) diff --git a/compile.rb b/compile.rb index f128cd0..f702ee1 100755 --- a/compile.rb +++ b/compile.rb @@ -4,33 +4,46 @@ require 'strscan' require 'pp' module Type + Nil = Struct.new(:value) Array = Struct.new(:type, :count) Record = Struct.new(:fields) Func = Struct.new(:args, :return) Ptr = Struct.new(:type) Int = Struct.new(:min, :max) - Real = Struct.new(:bits) + Float = Struct.new(:bits) end module Ast + Nil = Struct.new(:value) Val = Struct.new(:type, :value) + Apply = Struct.new(:type, :func, :args) + Return = Struct.new(:type, :val) end BuiltinSyms = { + "Nil" => { + :kind => :type, + :type => Type::Nil.new(0), + }, +# "nil" => { +# :kind => :const, +# :type => "Nil", +# :value => Ast::Val.new("Nil", 0) +# }, "Bool" => { kind: :type, type: Type::Int.new(0, 1) }, - "true" => { - kind: :const, - type: "Bool", - value: Ast::Val.new("Bool", 1) - }, - "false" => { - kind: :const, - type: "Bool", - value: Ast::Val.new("Bool", 0) - }, +# "true" => { +# kind: :const, +# type: "Bool", +# value: Ast::Val.new("Bool", 1) +# }, +# "false" => { +# kind: :const, +# type: "Bool", +# value: Ast::Val.new("Bool", 0) +# }, "Char" => { kind: :type, type: Type::Int.new(0, 0x10FFFF) @@ -39,14 +52,18 @@ BuiltinSyms = { kind: :type, type: Type::Int.new(-2**63-1, 2**63-1) }, - "Real" => { + "Float" => { kind: :type, - type: Type::Real.new(64) + type: Type::Float.new(64) }, "Byte" => { kind: :type, type: Type::Int.new(0, 255) }, + "String" => { + kind: :type, + type: Type::Array.new("Byte", nil) + }, } class Lexer @@ -56,10 +73,15 @@ class Lexer BRACES = /[\(\)\[\]\{\}]/ OPERATORS = /[*\/=+-:\$]/ INTEGER = /[0-9]+/ + STRING = /"(\\"|[^"])*"/ ID_TYPES = { "module" => :module, "imports" => :imports, - "is" => :is + "is" => :is, + "nil" => :nil, + "true" => :bool, + "false" => :bool, + "return" => :return, } def initialize(path) @@ -80,6 +102,8 @@ class Lexer type = get_id_type(@data.matched) elsif @data.scan(INTEGER) type = :int + elsif @data.scan(STRING) + type = :string elsif @data.scan(BRACES) type = @data.matched elsif @data.scan(OPERATORS) @@ -111,12 +135,18 @@ class Parser LVLNAMES = LEVELS.keys RULES = { - "(" => { 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 }, - :int => { 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 }, + :nil => { prefix: :constant, infix: nil, level: :none }, + :bool => { prefix: :constant, infix: nil, level: :none }, + :int => { prefix: :constant, infix: nil, level: :none }, + :float => { 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 }, } def initialize(path) @@ -238,8 +268,7 @@ class Parser sym[:type] = Type::Func.new([], nil) func_args(sym) sym[:type].return = type_specifier() if accept(":") - expect("{") - expect("}") + block(sym) end def func_args(sym) @@ -254,17 +283,112 @@ class Parser expect(")") end - def func_body(sym) + def block(sym) + sym[:value] = [] expect("{") + while !matches("}") + sym[:value] << statement() + end expect("}") end + ####################################### + # Statement Parsing + ####################################### + def statement() + puts "statement" + if matches(:return) + expect(:return) + expr = expression() + Ast::Return.new(expr[:type], expr) + elsif matches(:if) + elseif matches(:ident) + # declaration + # assignment + # procedure call + else + error("invalid statment") + end + end + ####################################### # Expression Parsing ####################################### def expression() - expect("{") - expect("}") + parseLevel(:assign) + end + + def getRule(tok) + RULES[tok.type] || {} + end + + def keepGoing(level) + rule = getRule(peek()) + (LEVELS[level] <= LEVELS[rule[:level]]) if rule.keys.length > 0 + end + + def parseLevel(level) + consume() + prefixRule = getRule(@prev)[:prefix] + error("error parsing expression") if not prefixRule + ast = send(prefixRule) + while keepGoing(level) + consume() + infixRule = getRule(@prev)[:infix] + ast = send(infixRule, ast) + end + ast + end + + def constant() + if (@prev.type == :int || @prev.type == :byte) + val = @prev.text.to_i + if @prev.type == :byte + error("invalid byte value") if (val < 0 || val > 255) + end + Ast::Val.new(Type::Int, ) + elsif (@prev.type == :string) + Ast::Val.new("String", @prev.text) + elsif (@prev.type == :nil) + Ast::Val.new("Nil", 0) + elsif (@prev.type == :bool) + Ast::Val.new("Bool", @prev.text == "true") + elsif (@prev.type == :float) + error("no float support yet") + elsif (@prev.type == :char) + error("no char support yet") + else + error("not a valid constant") + end + end + + def grouping() + ast = expression() + expect(")") + ast + end + + def func_call(ast) + expect(")") + Ast::Apply.new(nil, ast, []) + end + + def unary() + type = @prev.type + Ast::Apply.new(nil, @prev.type, [parseLevel(:unary)]) + end + + def nextLevel(tok) + level = getRule(@prev)[:level] + index = LVLNAMES.find_index(level) + LVLNAMES[index + 1] + end + + def binary(left) + type = @prev.type + nlvl = nextLevel(type) + right = parseLevel(nlvl) + Ast::Apply.new(nil, type, [left, right]) end ####################################### diff --git a/example.src b/example.src index ec09af4..12e1857 100644 --- a/example.src +++ b/example.src @@ -1,13 +1,16 @@ module Main imports (X11, XSel, Posix) -cmd : [String] = [ "fetch", nil, nil ] +cmd : [String] = true -#fetchsel(sel : String) -#{ +#[ "fetch", nil, nil ] + +fetchsel(sel : String) +{ + return 0 ## cmd[1] = sel; ## Posix.exec(cmd) -#} +} # #$main(args : array of String) : Int #{ -- 2.49.0