2016-07-03 23 views
1

我正在使用RexRacc創建我自己的語言,但我陷入了困境。我不知道如何添加函數或任何類型的不會像lambda一樣立即執行的代碼。我在語言中添加了塊/ lambda表達式,但塊中的任何內容都會立即執行。我怎麼能做出一個塊/ lambda,它可以在任何時候運行多次,並有它自己的範圍?或者甚至像if語句那樣,只在語句爲真時才執行「block」?將lambda添加到我的編程語言中

這裏是我的代碼:

lexer.rex:

class MyLang 
macro 
    BLANK [\s]+ 
    VAR [a-zA-Z_]\w* 
    NUMBER \d+ 
    MULTIPLY \* 
    DIVIDE \/ 
    ADD \+ 
    SUBTRACT \- 
    EQUALS = 
    LEFT_PARENTHESIS \(
    RIGHT_PARENTHESIS \) 
    STRING ("([^"]|\\")*?(?<!\\)")|('([^']|\\')*?(?<!\\)') 
    CURLY_BRACKET_L { 
    CURLY_BRACKET_R } 

rule 
    {BLANK} 
    {VAR} { [:VAR, text.to_sym] } 
    {NUMBER} { [:NUMBER, text.to_i] } 
    {MULTIPLY} { [:MULTIPLY, text.to_sym] } 
    {DIVIDE} { [:DIVIDE, text.to_sym] } 
    {ADD} { [:ADD, text.to_sym] } 
    {SUBTRACT} { [:SUBTRACT, text.to_sym] } 
    {EQUALS} { [:EQUALS, text.to_sym] } 
    {LEFT_PARENTHESIS} { [:LEFT_PARENTHESIS, text.to_sym] } 
    {RIGHT_PARENTHESIS} { [:RIGHT_PARENTHESIS, text.to_sym] } 
    {STRING} { [:STRING, text] } 
    {CURLY_BRACKET_L} { [:CURLY_BRACKET_L, text.to_sym] } 
    {CURLY_BRACKET_R} { [:CURLY_BRACKET_R, text.to_sym] } 

inner 
    def tokenize(code) 
     scan_setup(code) 
     tokens = [] 
     while token = next_token 
      tokens << token 
     end 
     tokens 
    end 

end 

parser.y:

class MyLang 
prechigh 
    left LEFT_PARENTHESIS 
    left RIGHT_PARENTHESIS 
    left MULTIPLY 
    left DIVIDE 
    left ADD 
    left SUBTRACT 
    right EQUALS 
preclow 

rule 
    expression : value 
    | block 

    value : NUMBER { return Value.new(val[0], "Number") } 
    | STRING { return Value.new(MyLangCore.str_escape(val[0]), "String") } 
    | assignment 
    | value MULTIPLY value { return MyLangCore.binary_operator(val[0], val[2], val[1]) } 
    | value DIVIDE value { return MyLangCore.binary_operator(val[0], val[2], val[1]) } 
    | value ADD value { return MyLangCore.binary_operator(val[0], val[2], val[1]) } 
    | value SUBTRACT value { return MyLangCore.binary_operator(val[0], val[2], val[1]) } 
    | LEFT_PARENTHESIS value RIGHT_PARENTHESIS { return val[1] } 
    | VAR { return MyLangCore.get_var(val[0]) } 

    assignment : VAR EQUALS value { return MyLangCore.new_variable(val[0], val[2]) } 

    block : CURLY_BRACKET_L expression CURLY_BRACKET_R 

end 

---- header 
    require_relative "lexer" 
    require_relative "my_lang_core" 

---- inner 
    def parse(input) 
     scan_str(input) 
    end 

這是我如何評價我的語言:

#!/usr/bin/env ruby 

require_relative "parser.rb" 
require "minitest/autorun" 

# check for errors once they exist 
describe MyLang do 

    before do 
     @parser = MyLang.new 
    end 

    describe "variables" do 
     it "assigns usable variables" do 
      @parser.parse("a = 4") 
      @parser.parse("a").value.must_equal 4 
     end 

     it "does complex assignments" do 
      @parser.parse("a = (4 + 8) * 2") 
      @parser.parse("b = 2 * (c = a + 1) + 1") 
      @parser.parse("a").value.must_equal 24 
      @parser.parse("b").value.must_equal 51 
      @parser.parse("c").value.must_equal 25 
     end 

     it "allows cool variable names" do 
      @parser.parse("_123 = 74") 
      @parser.parse("_123").value.must_equal 74 
     end 
    end 

    describe "PEMDAS" do 
     it "does math" do 
      @parser.parse("10 + 12 * 3 + 2").value.must_equal 48 
     end 

     it "does simple parentheses" do 
      @parser.parse("(1)").value.must_equal 1 
     end 

     it "uses parentheses" do 
      @parser.parse("(10 + 12) * 3 + 2").value.must_equal 68 
     end 

     it "does multi-level parentheses" do 
      @parser.parse("(3 - (2 - 1)) * 4").value.must_equal 8 
     end 
    end 

    describe "strings" do 
     it "parses strings" do 
      @parser.parse(%{'hello world.'}).value.must_equal "hello world." 
      @parser.parse(%{"hello world."}).value.must_equal "hello world." 
      @parser.parse(%{''}).value.must_equal "" 
     end 

     it "assigns strings" do 
      @parser.parse("a = 'hey'") 
      @parser.parse("a").value.must_equal "hey" 
     end 

     # TODO: fix 
     # it "handles escape charectors" do 
     # @parser.parse(%{"hey\\"\\n"}).value.must_equal "hey\"\n" 
     # end 

     it "adds strings" do 
      @parser.parse(%{"Hello, " + "world" + "!"}).value.must_equal "Hello, world!" 
     end 

     it "multiplies strings" do 
      @parser.parse(%{"1" * 3}).value.must_equal "111" 
     end 

     it "adds and multiplies" do 
      @parser.parse(%{("Na" + "N ") * 3 + "!"}).value.must_equal "NaN NaN NaN !" 
     end 
    end 

    # this is what I need to implement 
    describe "blocks" do 
     @parser.parse("{ a, b in a + b }(5, 4)") 
    end 

end 

l = MyLang.new 
p l.parse("{ 1 + 2 }") 
+0

解析器看起來很好(並且對代碼的執行順序沒有太大影響)。您需要向我們展示您的評估方法。 – sepp2k

+0

謝謝,我剛剛補充說。 – Addison

+0

評價方法的含義是採用解析器生成的中間表示並執行它的代碼,但我現在意識到您並未創建中間表示。所以'MyLangCore'方法直接執行給定的操作,對吧? – sepp2k

回答

2

考試使用的方法Racc wiki中的表達式(在解析過程中直接評估表達式)僅適用於簡單表達式評估程序。您一旦添加任何類型的控制流程,就會停止工作 - 正如您已經注意到的那樣。

實現解釋器的常用方法是讓解析器構造源代碼的某種中間表示形式 - 通常是抽象語法樹或某種字節碼。解析完這個表示然後作爲一個單獨的步驟執行。

+0

謝謝,我會試着讓解析器創建某種語法樹,我會讓你知道它結果! – Addison

+0

我完成了這個工作,它工作的很好,非常感謝! – Addison