Добавление лямбд к моему языку программирования

Я работаю над созданием собственного языка с использованием Rex и Racc, но я застрял. Я не уверен, как добавить функции или любой другой код, который не будет немедленно выполнен как лямбда. Я добавил блоки / лямбды в язык, но все, что находится в блоке, выполняется немедленно. Как я могу сделать блок / лямбду, который может быть запущен в любое время, несколько раз и имеет свою собственную область? Или даже что-то вроде оператора if, где "блок" выполняется только в том случае, если оператор верен?

Вот мой код:

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 }")

1 ответ

Решение

Подход, использованный примером в вики Racc (где выражения оцениваются непосредственно во время синтаксического анализа), работает только для простых оценщиков выражений. Как только вы добавляете какой-либо тип потока управления, он перестает работать - как вы заметили.

Обычный способ реализации интерпретаторов - позволить синтаксическому анализатору создать какое-то промежуточное представление исходного кода - обычно абстрактное синтаксическое дерево или какой-то байт-код. После разбора это представление затем выполняется как отдельный шаг.

Другие вопросы по тегам