Rename AST generation mode to tree generation mode
This commit is contained in:
1 parent
6a87bb2d56
commit
77ec7c9de4
34 files changed
+279
-279
No files matched your search
@@ -298,7 +298,7 @@ class Propane
|
||||
end
|
||||
else
|
||||
code = code.gsub(/\$\$/) do |match|
|
||||
if @grammar.ast
|
||||
if @grammar.tree
|
||||
case @language
|
||||
when "c"
|
||||
"out_token_info->pvalue"
|
||||
|
||||
+29
-29
@@ -5,9 +5,9 @@ class Propane
|
||||
# Reserve identifiers beginning with a double-underscore for internal use.
|
||||
IDENTIFIER_REGEX = /(?:[a-zA-Z]|_[a-zA-Z0-9])[a-zA-Z_0-9]*/
|
||||
|
||||
attr_reader :ast
|
||||
attr_reader :ast_prefix
|
||||
attr_reader :ast_suffix
|
||||
attr_reader :tree
|
||||
attr_reader :tree_prefix
|
||||
attr_reader :tree_suffix
|
||||
attr_reader :free_token_node
|
||||
attr_reader :modulename
|
||||
attr_reader :patterns
|
||||
@@ -30,9 +30,9 @@ class Propane
|
||||
@input = input.gsub("\r\n", "\n")
|
||||
@ptypes = {"default" => "void *"}
|
||||
@prefix = "p_"
|
||||
@ast = false
|
||||
@ast_prefix = ""
|
||||
@ast_suffix = ""
|
||||
@tree = false
|
||||
@tree_prefix = ""
|
||||
@tree_suffix = ""
|
||||
@free_token_node = nil
|
||||
parse_grammar!
|
||||
@start_rules << "Start" if @start_rules.empty?
|
||||
@@ -62,9 +62,9 @@ class Propane
|
||||
if parse_white_space!
|
||||
elsif parse_comment_line!
|
||||
elsif @modeline.nil? && parse_mode_label!
|
||||
elsif parse_ast_statement!
|
||||
elsif parse_ast_prefix_statement!
|
||||
elsif parse_ast_suffix_statement!
|
||||
elsif parse_tree_statement!
|
||||
elsif parse_tree_prefix_statement!
|
||||
elsif parse_tree_suffix_statement!
|
||||
elsif parse_free_token_node_statement!
|
||||
elsif parse_module_statement!
|
||||
elsif parse_ptype_statement!
|
||||
@@ -98,21 +98,21 @@ class Propane
|
||||
consume!(/#.*\n/)
|
||||
end
|
||||
|
||||
def parse_ast_statement!
|
||||
if consume!(/ast\s*;/)
|
||||
@ast = true
|
||||
def parse_tree_statement!
|
||||
if consume!(/tree\s*;/)
|
||||
@tree = true
|
||||
end
|
||||
end
|
||||
|
||||
def parse_ast_prefix_statement!
|
||||
if md = consume!(/ast_prefix\s+(\w+)\s*;/)
|
||||
@ast_prefix = md[1]
|
||||
def parse_tree_prefix_statement!
|
||||
if md = consume!(/tree_prefix\s+(\w+)\s*;/)
|
||||
@tree_prefix = md[1]
|
||||
end
|
||||
end
|
||||
|
||||
def parse_ast_suffix_statement!
|
||||
if md = consume!(/ast_suffix\s+(\w+)\s*;/)
|
||||
@ast_suffix = md[1]
|
||||
def parse_tree_suffix_statement!
|
||||
if md = consume!(/tree_suffix\s+(\w+)\s*;/)
|
||||
@tree_suffix = md[1]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -136,8 +136,8 @@ class Propane
|
||||
if consume!(/ptype\s+/)
|
||||
name = "default"
|
||||
if md = consume!(/(#{IDENTIFIER_REGEX})\s*=\s*/)
|
||||
if @ast
|
||||
raise Error.new("Multiple ptypes are unsupported in AST mode")
|
||||
if @tree
|
||||
raise Error.new("Multiple ptypes are unsupported in tree mode")
|
||||
end
|
||||
name = md[1]
|
||||
end
|
||||
@@ -151,8 +151,8 @@ class Propane
|
||||
md = consume!(/(#{IDENTIFIER_REGEX})\s*/, "expected token name")
|
||||
name = md[1]
|
||||
if md = consume!(/\((#{IDENTIFIER_REGEX})\)\s*/)
|
||||
if @ast
|
||||
raise Error.new("Multiple ptypes are unsupported in AST mode")
|
||||
if @tree
|
||||
raise Error.new("Multiple ptypes are unsupported in tree mode")
|
||||
end
|
||||
ptypename = md[1]
|
||||
end
|
||||
@@ -175,8 +175,8 @@ class Propane
|
||||
md = consume!(/(#{IDENTIFIER_REGEX})\s*/, "expected token name")
|
||||
name = md[1]
|
||||
if md = consume!(/\((#{IDENTIFIER_REGEX})\)\s*/)
|
||||
if @ast
|
||||
raise Error.new("Multiple ptypes are unsupported in AST mode")
|
||||
if @tree
|
||||
raise Error.new("Multiple ptypes are unsupported in tree mode")
|
||||
end
|
||||
ptypename = md[1]
|
||||
end
|
||||
@@ -205,12 +205,12 @@ class Propane
|
||||
def parse_rule_statement!
|
||||
if md = consume!(/(#{IDENTIFIER_REGEX})\s*(?:\((#{IDENTIFIER_REGEX})\))?\s*->\s*/)
|
||||
rule_name, ptypename = *md[1, 2]
|
||||
if @ast && ptypename
|
||||
raise Error.new("Multiple ptypes are unsupported in AST mode")
|
||||
if @tree && ptypename
|
||||
raise Error.new("Multiple ptypes are unsupported in tree mode")
|
||||
end
|
||||
md = consume!(/((?:#{IDENTIFIER_REGEX}\??(?::#{IDENTIFIER_REGEX})?\s*)*)\s*/, "expected rule component list")
|
||||
components = md[1].strip.split(/\s+/)
|
||||
if @ast
|
||||
if @tree
|
||||
consume!(/;/, "expected `;'")
|
||||
else
|
||||
unless code = parse_code_block!
|
||||
@@ -227,8 +227,8 @@ class Propane
|
||||
if pattern = parse_pattern!
|
||||
consume!(/\s+/)
|
||||
if md = consume!(/\((#{IDENTIFIER_REGEX})\)\s*/)
|
||||
if @ast
|
||||
raise Error.new("Multiple ptypes are unsupported in AST mode")
|
||||
if @tree
|
||||
raise Error.new("Multiple ptypes are unsupported in tree mode")
|
||||
end
|
||||
ptypename = md[1]
|
||||
end
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ class Propane
|
||||
|
||||
# @return [Array<Integer>]
|
||||
# Map this rule's components to their positions in the parent RuleSet's
|
||||
# node field pointer array. This is used for AST construction.
|
||||
# node field pointer array. This is used for tree construction.
|
||||
attr_accessor :rule_set_node_field_index_map
|
||||
|
||||
# Construct a Rule.
|
||||
|
||||
+23
-23
@@ -4,8 +4,8 @@ class Propane
|
||||
class RuleSet
|
||||
|
||||
# @return [Array<Hash>]
|
||||
# AST fields.
|
||||
attr_reader :ast_fields
|
||||
# tree fields.
|
||||
attr_reader :tree_fields
|
||||
|
||||
# @return [Integer]
|
||||
# ID of the RuleSet.
|
||||
@@ -100,28 +100,28 @@ class Propane
|
||||
|
||||
# Finalize a RuleSet after adding all Rules to it.
|
||||
def finalize(grammar)
|
||||
if grammar.ast
|
||||
build_ast_fields(grammar)
|
||||
if grammar.tree
|
||||
build_tree_fields(grammar)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Build the set of AST fields for this RuleSet.
|
||||
# Build the set of tree fields for this RuleSet.
|
||||
#
|
||||
# This is an Array of Hashes. Each entry in the Array corresponds to a
|
||||
# field location in the AST node. The entry is a Hash. It could have one or
|
||||
# field location in the tree node. The entry is a Hash. It could have one or
|
||||
# two keys. It will always have the field name with a positional suffix as
|
||||
# a key. It may also have the field name without the positional suffix if
|
||||
# that field only exists in one position across all Rules in the RuleSet.
|
||||
#
|
||||
# @return [void]
|
||||
def build_ast_fields(grammar)
|
||||
field_ast_node_indexes = {}
|
||||
def build_tree_fields(grammar)
|
||||
field_tree_node_indexes = {}
|
||||
field_indexes_across_all_rules = {}
|
||||
# Stores the index into @ast_fields by field alias name.
|
||||
# Stores the index into @tree_fields by field alias name.
|
||||
field_aliases = {}
|
||||
@ast_fields = []
|
||||
@tree_fields = []
|
||||
@rules.each do |rule|
|
||||
rule.components.each_with_index do |component, i|
|
||||
if component.is_a?(RuleSet) && component.optional?
|
||||
@@ -132,25 +132,25 @@ class Propane
|
||||
else
|
||||
node_name = component.name
|
||||
end
|
||||
struct_name = "#{grammar.ast_prefix}#{node_name}#{grammar.ast_suffix}"
|
||||
struct_name = "#{grammar.tree_prefix}#{node_name}#{grammar.tree_suffix}"
|
||||
field_name = "p#{node_name}#{i + 1}"
|
||||
unless field_ast_node_indexes[field_name]
|
||||
field_ast_node_indexes[field_name] = @ast_fields.size
|
||||
@ast_fields << {field_name => struct_name}
|
||||
unless field_tree_node_indexes[field_name]
|
||||
field_tree_node_indexes[field_name] = @tree_fields.size
|
||||
@tree_fields << {field_name => struct_name}
|
||||
end
|
||||
rule.aliases.each do |alias_name, index|
|
||||
if index == i
|
||||
alias_ast_fields_index = field_ast_node_indexes[field_name]
|
||||
if field_aliases[alias_name] && field_aliases[alias_name] != alias_ast_fields_index
|
||||
raise Error.new("Error: conflicting AST node field positions for alias `#{alias_name}` in rule #{rule.name} defined on line #{rule.line_number}")
|
||||
alias_tree_fields_index = field_tree_node_indexes[field_name]
|
||||
if field_aliases[alias_name] && field_aliases[alias_name] != alias_tree_fields_index
|
||||
raise Error.new("Error: conflicting tree node field positions for alias `#{alias_name}` in rule #{rule.name} defined on line #{rule.line_number}")
|
||||
end
|
||||
field_aliases[alias_name] = alias_ast_fields_index
|
||||
@ast_fields[alias_ast_fields_index][alias_name] = @ast_fields[alias_ast_fields_index].first[1]
|
||||
field_aliases[alias_name] = alias_tree_fields_index
|
||||
@tree_fields[alias_tree_fields_index][alias_name] = @tree_fields[alias_tree_fields_index].first[1]
|
||||
end
|
||||
end
|
||||
field_indexes_across_all_rules[node_name] ||= Set.new
|
||||
field_indexes_across_all_rules[node_name] << field_ast_node_indexes[field_name]
|
||||
rule.rule_set_node_field_index_map[i] = field_ast_node_indexes[field_name]
|
||||
field_indexes_across_all_rules[node_name] << field_tree_node_indexes[field_name]
|
||||
rule.rule_set_node_field_index_map[i] = field_tree_node_indexes[field_name]
|
||||
end
|
||||
end
|
||||
field_indexes_across_all_rules.each do |node_name, indexes_across_all_rules|
|
||||
@@ -158,8 +158,8 @@ class Propane
|
||||
# If this field was only seen in one position across all rules,
|
||||
# then add an alias to the positional field name that does not
|
||||
# include the position.
|
||||
@ast_fields[indexes_across_all_rules.first]["p#{node_name}"] =
|
||||
"#{grammar.ast_prefix}#{node_name}#{grammar.ast_suffix}"
|
||||
@tree_fields[indexes_across_all_rules.first]["p#{node_name}"] =
|
||||
"#{grammar.tree_prefix}#{node_name}#{grammar.tree_suffix}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in new issue
Block a user