Assign pattern code IDs in Generator instead of Grammar

This commit is contained in:
Josh Holtrop 2022-10-01 10:36:35 -04:00
parent e7e30c4f28
commit 150be33826
4 changed files with 17 additions and 19 deletions

View File

@ -28,6 +28,7 @@ class Propane
def process_grammar!
tokens_by_name = {}
@grammar.tokens.each do |token|
# Check for token name conflicts.
if tokens_by_name.include?(token.name)
raise Error.new("Duplicate token name #{token.name.inspect}")
end
@ -35,9 +36,11 @@ class Propane
end
rule_sets = {}
@grammar.rules.each do |rule|
# Check for token/rule name conflict.
if tokens_by_name.include?(rule.name)
raise Error.new("Rule name collides with token name #{rule.name.inspect}")
end
# Build rule sets of all rules with the same name.
@_rule_set_id ||= @grammar.tokens.size
unless rule_sets[rule.name]
rule_sets[rule.name] = RuleSet.new(rule.name, @_rule_set_id)
@ -46,9 +49,17 @@ class Propane
rule.rule_set = rule_sets[rule.name]
rule_sets[rule.name] << rule
end
# Check for start rule.
unless rule_sets["Start"]
raise Error.new("Start rule not found")
end
# Generate lexer user code IDs for lexer patterns with user code blocks.
@grammar.patterns.select do |pattern|
pattern.code
end.each_with_index do |pattern, code_id|
pattern.code_id = code_id
end
# Map rule components from names to Token/RuleSet objects.
@grammar.rules.each do |rule|
rule.components.map! do |component|
if tokens_by_name[component]
@ -61,7 +72,9 @@ class Propane
end
end
determine_possibly_empty_rulesets!(rule_sets)
# Generate the lexer.
@lexer = Lexer.new(@grammar.patterns)
# Generate the parser.
@parser = Parser.new(@grammar, rule_sets, rule_sets["Start"], @log)
end

View File

@ -12,7 +12,6 @@ class Propane
@patterns = []
@tokens = []
@rules = []
@code_id = 0
@line_number = 1
@next_line_number = @line_number
@input = input.gsub("\r\n", "\n")
@ -78,15 +77,12 @@ class Propane
end
pattern ||= name
consume!(/\s+/)
if code = parse_code_block!
code_id = @code_id
@code_id += 1
else
unless code = parse_code_block!
consume!(/;/, "expected pattern or `;' or code block")
end
token = Token.new(name: name, id: @tokens.size, line_number: @line_number)
@tokens << token
pattern = Pattern.new(pattern: pattern, token: token, line_number: @line_number, code: code, code_id: code_id)
pattern = Pattern.new(pattern: pattern, token: token, line_number: @line_number, code: code)
@patterns << pattern
end
end
@ -132,9 +128,7 @@ class Propane
unless code = parse_code_block!
raise Error.new("Line #{@line_number}: expected code block to follow pattern")
end
code_id = @code_id
@code_id += 1
@patterns << Pattern.new(pattern: pattern, line_number: @line_number, code: code, code_id: code_id)
@patterns << Pattern.new(pattern: pattern, line_number: @line_number, code: code)
end
end

View File

@ -8,7 +8,7 @@ class Propane
# @option options [Integer, nil] :code_id
# Code block ID.
attr_reader :code_id
attr_accessor :code_id
# @return [String, nil]
# Pattern.
@ -32,8 +32,6 @@ class Propane
# Optional parameters.
# @option options [String, nil] :code
# Code block to execute when the pattern is matched.
# @option options [Integer, nil] :code_id
# Code block ID.
# @option options [Boolean] :drop
# Whether this is a drop pattern.
# @option options [String, nil] :pattern
@ -44,7 +42,6 @@ class Propane
# Line number where the token was defined in the input grammar.
def initialize(options)
@code = options[:code]
@code_id = options[:code_id]
@drop = options[:drop]
@pattern = options[:pattern]
@token = options[:token]

View File

@ -41,7 +41,6 @@ EOF
expect(o).to_not be_nil
expect(o.pattern).to eq "while"
expect(o.line_number).to eq 6
expect(o.code_id).to be_nil
expect(o.code).to be_nil
o = grammar.tokens.find {|token| token.name == "id"}
@ -53,7 +52,6 @@ EOF
expect(o).to_not be_nil
expect(o.pattern).to eq "[a-zA-Z_][a-zA-Z_0-9]*"
expect(o.line_number).to eq 9
expect(o.code_id).to be_nil
expect(o.code).to be_nil
o = grammar.tokens.find {|token| token.name == "token_with_code"}
@ -65,7 +63,6 @@ EOF
expect(o).to_not be_nil
expect(o.pattern).to eq "token_with_code"
expect(o.line_number).to eq 11
expect(o.code_id).to eq 0
expect(o.code).to eq "Code for the token\n"
o = grammar.tokens.find {|token| token.name == "token_with_no_pattern"}
@ -79,7 +76,6 @@ EOF
expect(o).to_not be_nil
expect(o.line_number).to eq 17
expect(o.token).to be_nil
expect(o.code_id).to be_nil
expect(o.code).to be_nil
expect(grammar.rules.size).to eq 3
@ -128,7 +124,6 @@ EOF
o = grammar.patterns.find {|pattern| pattern.token == o}
expect(o).to_not be_nil
expect(o.code_id).to eq 0
expect(o.code).to eq " a = b;\n return c;\n"
o = grammar.tokens.find {|token| token.name == "code2"}
@ -138,7 +133,6 @@ EOF
o = grammar.patterns.find {|pattern| pattern.token == o}
expect(o).to_not be_nil
expect(o.code_id).to eq 1
expect(o.code).to eq %[ writeln("Hello there");\n]
end
end