From 77ec7c9de462620f02915af8e8cd1fc887572194 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 9 Feb 2026 21:59:00 -0500 Subject: [PATCH] Rename AST generation mode to tree generation mode --- README.md | 2 +- assets/parser.c.erb | 98 +++++++++---------- assets/parser.d.erb | 78 +++++++-------- assets/parser.h.erb | 34 +++---- doc/user_guide.md | 88 ++++++++--------- extra/vim/syntax/propane.vim | 2 +- lib/propane/generator.rb | 2 +- lib/propane/grammar.rb | 58 +++++------ lib/propane/rule.rb | 2 +- lib/propane/rule_set.rb | 46 ++++----- spec/propane_spec.rb | 90 ++++++++--------- ...y.c => test_free_tree_token_node_memory.c} | 2 +- ...test_named_optional_rule_component_tree.c} | 6 +- ...test_named_optional_rule_component_tree.d} | 0 ....c => test_optional_rule_component_tree.c} | 6 +- ....d => test_optional_rule_component_tree.d} | 0 ...tart_rule_ast.c => test_start_rule_tree.c} | 2 +- ...tart_rule_ast.d => test_start_rule_tree.d} | 0 ...rules_ast.c => test_starting_rules_tree.c} | 6 +- ...rules_ast.d => test_starting_rules_tree.d} | 0 spec/{test_ast.c => test_tree.c} | 6 +- spec/{test_ast.d => test_tree.d} | 0 ...ld_aliases.c => test_tree_field_aliases.c} | 2 +- ...ld_aliases.d => test_tree_field_aliases.d} | 0 ...itions.c => test_tree_invalid_positions.c} | 8 +- ...itions.d => test_tree_invalid_positions.d} | 0 ...ains.c => test_tree_node_memory_remains.c} | 2 +- ...ains.d => test_tree_node_memory_remains.d} | 0 spec/{test_ast_ps.c => test_tree_ps.c} | 6 +- spec/{test_ast_ps.d => test_tree_ps.d} | 0 ...ositions.c => test_tree_token_positions.c} | 4 +- ...ositions.d => test_tree_token_positions.d} | 0 ...ane => tree_node_memory_remains.c.propane} | 4 +- ...ane => tree_node_memory_remains.d.propane} | 4 +- 34 files changed, 279 insertions(+), 279 deletions(-) rename spec/{test_free_ast_token_node_memory.c => test_free_tree_token_node_memory.c} (94%) rename spec/{test_named_optional_rule_component_ast.c => test_named_optional_rule_component_tree.c} (94%) rename spec/{test_named_optional_rule_component_ast.d => test_named_optional_rule_component_tree.d} (100%) rename spec/{test_optional_rule_component_ast.c => test_optional_rule_component_tree.c} (94%) rename spec/{test_optional_rule_component_ast.d => test_optional_rule_component_tree.d} (100%) rename spec/{test_start_rule_ast.c => test_start_rule_tree.c} (94%) rename spec/{test_start_rule_ast.d => test_start_rule_tree.d} (100%) rename spec/{test_starting_rules_ast.c => test_starting_rules_tree.c} (93%) rename spec/{test_starting_rules_ast.d => test_starting_rules_tree.d} (100%) rename spec/{test_ast.c => test_tree.c} (96%) rename spec/{test_ast.d => test_tree.d} (100%) rename spec/{test_ast_field_aliases.c => test_tree_field_aliases.c} (95%) rename spec/{test_ast_field_aliases.d => test_tree_field_aliases.d} (100%) rename spec/{test_ast_invalid_positions.c => test_tree_invalid_positions.c} (97%) rename spec/{test_ast_invalid_positions.d => test_tree_invalid_positions.d} (100%) rename spec/{test_ast_node_memory_remains.c => test_tree_node_memory_remains.c} (99%) rename spec/{test_ast_node_memory_remains.d => test_tree_node_memory_remains.d} (100%) rename spec/{test_ast_ps.c => test_tree_ps.c} (96%) rename spec/{test_ast_ps.d => test_tree_ps.d} (100%) rename spec/{test_ast_token_positions.c => test_tree_token_positions.c} (98%) rename spec/{test_ast_token_positions.d => test_tree_token_positions.d} (100%) rename spec/{ast_node_memory_remains.c.propane => tree_node_memory_remains.c.propane} (99%) rename spec/{ast_node_memory_remains.d.propane => tree_node_memory_remains.d.propane} (99%) diff --git a/README.md b/README.md index dc8befb..c2c92a8 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Propane is a LALR Parser Generator (LPG) which: * supports UTF-8 lexer inputs * generates a table-driven shift/reduce parser to parse input in linear time * targets C, C++, or D language outputs - * optionally supports automatic full AST generation + * optionally supports automatic full parse tree generation * is MIT-licensed * is distributable as a standalone Ruby script diff --git a/assets/parser.c.erb b/assets/parser.c.erb index f70532a..130883c 100644 --- a/assets/parser.c.erb +++ b/assets/parser.c.erb @@ -638,7 +638,7 @@ typedef struct * reduce action. */ parser_state_id_t n_states; -<% if @grammar.ast %> +<% if @grammar.tree %> /** * Map of rule components to rule set child fields. @@ -646,7 +646,7 @@ typedef struct uint16_t const * rule_set_node_field_index_map; /** - * Number of rule set AST node fields. + * Number of rule set tree node fields. */ uint16_t rule_set_node_field_array_size; @@ -688,21 +688,21 @@ typedef struct /** Parser value from this state. */ <%= @grammar.prefix %>value_t pvalue; -<% if @grammar.ast %> - /** AST node. */ - void * ast_node; +<% if @grammar.tree %> + /** tree node. */ + void * tree_node; <% end %> } state_value_t; -/** Common AST node structure. */ -typedef struct ASTNode_s +/** Common tree node structure. */ +typedef struct TreeNode_s { <%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t end_position; uint16_t n_fields; uint8_t is_token; - struct ASTNode_s * fields[]; -} ASTNode; + struct TreeNode_s * fields[]; +} TreeNode; /** Parser shift table. */ static const shift_t parser_shift_table[] = { @@ -711,7 +711,7 @@ static const shift_t parser_shift_table[] = { <% end %> }; -<% if @grammar.ast %> +<% if @grammar.tree %> <% @grammar.rules.each do |rule| %> <% unless rule.flat_rule_set_node_field_index_map? %> const uint16_t r_<%= rule.name.gsub("$", "_") %><%= rule.id %>_node_field_index_map[<%= rule.rule_set_node_field_index_map.size %>] = {<%= rule.rule_set_node_field_index_map.map {|v| v.to_s}.join(", ") %>}; @@ -726,14 +726,14 @@ static const reduce_t parser_reduce_table[] = { <%= reduce[:token_id] %>u, /* Token: <%= reduce[:token] ? reduce[:token].name : "(any)" %> */ <%= reduce[:rule_id] %>u, /* Rule ID */ <%= reduce[:rule_set_id] %>u, /* Rule set ID (<%= reduce[:rule].rule_set.name %>) */ -<% if @grammar.ast %> +<% if @grammar.tree %> <%= reduce[:n_states] %>u, /* Number of states */ <% if reduce[:rule].flat_rule_set_node_field_index_map? %> NULL, /* No rule set node field index map (flat map) */ <% else %> &r_<%= reduce[:rule].name.gsub("$", "_") %><%= reduce[:rule].id %>_node_field_index_map[0], /* Rule set node field index map */ <% end %> - <%= reduce[:rule].rule_set.ast_fields.size %>, /* Number of AST fields */ + <%= reduce[:rule].rule_set.tree_fields.size %>, /* Number of tree fields */ <%= reduce[:propagate_optional_target] %>}, /* Propagate optional target? */ <% else %> <%= reduce[:n_states] %>u}, @@ -841,7 +841,7 @@ static void state_values_stack_free(state_values_stack_t * stack) free(stack->entries); } -<% unless @grammar.ast %> +<% unless @grammar.tree %> /** * Execute user code associated with a parser rule. * @@ -944,7 +944,7 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start <%= @grammar.prefix %>token_t token = INVALID_TOKEN_ID; state_values_stack_t statevalues; size_t reduced_rule_set = INVALID_ID; -<% if @grammar.ast %> +<% if @grammar.tree %> void * reduced_parser_node; <% else %> <%= @grammar.prefix %>value_t reduced_parser_value; @@ -976,8 +976,8 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start if ((shift_state != INVALID_ID) && (token == TOKEN___EOF)) { /* Successful parse. */ -<% if @grammar.ast %> - context->parse_result = state_values_stack_index(&statevalues, -1)->ast_node; +<% if @grammar.tree %> + context->parse_result = state_values_stack_index(&statevalues, -1)->tree_node; <% else %> context->parse_result = state_values_stack_index(&statevalues, -1)->pvalue; <% end %> @@ -993,15 +993,15 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start if (reduced_rule_set == INVALID_ID) { /* We shifted a token, mark it consumed. */ -<% if @grammar.ast %> - <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %> * token_ast_node = (<%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %> *)malloc(sizeof(<%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %>)); - token_ast_node->position = token_info.position; - token_ast_node->end_position = token_info.end_position; - token_ast_node->n_fields = 0u; - token_ast_node->is_token = 1u; - token_ast_node->token = token; - token_ast_node->pvalue = token_info.pvalue; - state_values_stack_index(&statevalues, -1)->ast_node = token_ast_node; +<% if @grammar.tree %> + <%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> * token_tree_node = (<%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> *)malloc(sizeof(<%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %>)); + token_tree_node->position = token_info.position; + token_tree_node->end_position = token_info.end_position; + token_tree_node->n_fields = 0u; + token_tree_node->is_token = 1u; + token_tree_node->token = token; + token_tree_node->pvalue = token_info.pvalue; + state_values_stack_index(&statevalues, -1)->tree_node = token_tree_node; <% else %> state_values_stack_index(&statevalues, -1)->pvalue = token_info.pvalue; <% end %> @@ -1010,8 +1010,8 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start else { /* We shifted a RuleSet. */ -<% if @grammar.ast %> - state_values_stack_index(&statevalues, -1)->ast_node = reduced_parser_node; +<% if @grammar.tree %> + state_values_stack_index(&statevalues, -1)->tree_node = reduced_parser_node; <% else %> state_values_stack_index(&statevalues, -1)->pvalue = reduced_parser_value; <%= @grammar.prefix %>value_t new_parse_result; @@ -1027,16 +1027,16 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start if (reduce_index != INVALID_ID) { /* We have something to reduce. */ -<% if @grammar.ast %> +<% if @grammar.tree %> if (parser_reduce_table[reduce_index].propagate_optional_target) { - reduced_parser_node = state_values_stack_index(&statevalues, -1)->ast_node; + reduced_parser_node = state_values_stack_index(&statevalues, -1)->tree_node; } else if (parser_reduce_table[reduce_index].n_states > 0) { size_t n_fields = parser_reduce_table[reduce_index].rule_set_node_field_array_size; - size_t bytes = sizeof(ASTNode) + n_fields * sizeof(void *); - ASTNode * node = (ASTNode *)malloc(bytes); + size_t bytes = sizeof(TreeNode) + n_fields * sizeof(void *); + TreeNode * node = (TreeNode *)malloc(bytes); memset(node, 0, bytes); node->position = INVALID_POSITION; node->end_position = INVALID_POSITION; @@ -1045,20 +1045,20 @@ static size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t start { for (size_t i = 0; i < parser_reduce_table[reduce_index].n_states; i++) { - node->fields[i] = (ASTNode *)state_values_stack_index(&statevalues, -(int)parser_reduce_table[reduce_index].n_states + (int)i)->ast_node; + node->fields[i] = (TreeNode *)state_values_stack_index(&statevalues, -(int)parser_reduce_table[reduce_index].n_states + (int)i)->tree_node; } } else { for (size_t i = 0; i < parser_reduce_table[reduce_index].n_states; i++) { - node->fields[parser_reduce_table[reduce_index].rule_set_node_field_index_map[i]] = (ASTNode *)state_values_stack_index(&statevalues, -(int)parser_reduce_table[reduce_index].n_states + (int)i)->ast_node; + node->fields[parser_reduce_table[reduce_index].rule_set_node_field_index_map[i]] = (TreeNode *)state_values_stack_index(&statevalues, -(int)parser_reduce_table[reduce_index].n_states + (int)i)->tree_node; } } bool position_found = false; for (size_t i = 0; i < n_fields; i++) { - ASTNode * child = node->fields[i]; + TreeNode * child = node->fields[i]; if ((child != NULL) && <%= @grammar.prefix %>position_valid(child->position)) { if (!position_found) @@ -1125,15 +1125,15 @@ size_t <%= @grammar.prefix %>parse_<%= start_rule %>(<%= @grammar.prefix %>conte * * @return Parse result value. */ -<% if @grammar.ast %> -<%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context) +<% if @grammar.tree %> +<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context) { - return (<%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> *) context->parse_result; + return (<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> *) context->parse_result; } <% @grammar.start_rules.each_with_index do |start_rule, i| %> -<%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context) +<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context) { - return (<%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> *) context->parse_result; + return (<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> *) context->parse_result; } <% end %> <% else %> @@ -1184,14 +1184,14 @@ size_t <%= @grammar.prefix %>user_terminate_code(<%= @grammar.prefix %>context_t { return context->token; } -<% if @grammar.ast %> +<% if @grammar.tree %> -static void free_ast_node(ASTNode * node) +static void free_tree_node(TreeNode * node) { if (node->is_token) { <% if @grammar.free_token_node %> - <%= @grammar.free_token_node %>((<%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %> *) node); + <%= @grammar.free_token_node %>((<%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> *) node); <% end %> /* TODO: free value_t */ } @@ -1201,7 +1201,7 @@ static void free_ast_node(ASTNode * node) { if (node->fields[i] != NULL) { - free_ast_node(node->fields[i]); + free_tree_node(node->fields[i]); } } } @@ -1209,20 +1209,20 @@ static void free_ast_node(ASTNode * node) } /** - * Free all AST node memory. + * Free all tree node memory. */ -void <%= @grammar.prefix %>free_ast(<%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> * ast) +void <%= @grammar.prefix %>free_tree(<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> * tree) { - free_ast_node((ASTNode *)ast); + free_tree_node((TreeNode *)tree); } <% @grammar.start_rules.each_with_index do |start_rule, i| %> /** - * Free all AST node memory. + * Free all tree node memory. */ -void <%= @grammar.prefix %>free_ast_<%= start_rule %>(<%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> * ast) +void <%= @grammar.prefix %>free_tree_<%= start_rule %>(<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> * tree) { - free_ast_node((ASTNode *)ast); + free_tree_node((TreeNode *)tree); } <% end %> <% end %> diff --git a/assets/parser.d.erb b/assets/parser.d.erb index 99eac22..b00217f 100644 --- a/assets/parser.d.erb +++ b/assets/parser.d.erb @@ -75,7 +75,7 @@ public struct <%= @grammar.prefix %>position_t } } -<% if @grammar.ast %> +<% if @grammar.tree %> /** Parser values type. */ public alias <%= @grammar.prefix %>value_t = <%= @grammar.ptype %>; <% else %> @@ -88,19 +88,19 @@ public union <%= @grammar.prefix %>value_t } <% end %> -<% if @grammar.ast %> -/** Common AST node structure. */ -private struct ASTNode +<% if @grammar.tree %> +/** Common tree node structure. */ +private struct TreeNode { <%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t end_position; void *[0] fields; } -/** AST node types. @{ */ -public struct <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %> +/** Tree node types. @{ */ +public struct <%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> { - /* ASTNode fields must be present in the same order here. */ + /* TreeNode fields must be present in the same order here. */ <%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t end_position; <%= @grammar.prefix %>token_t token; @@ -110,11 +110,11 @@ public struct <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %> <% @parser.rule_sets.each do |name, rule_set| %> <% next if name.start_with?("$") %> <% next if rule_set.optional? %> -public struct <%= @grammar.ast_prefix %><%= name %><%= @grammar.ast_suffix %> +public struct <%= @grammar.tree_prefix %><%= name %><%= @grammar.tree_suffix %> { <%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t end_position; -<% rule_set.ast_fields.each do |fields| %> +<% rule_set.tree_fields.each do |fields| %> union { <% fields.each do |field_name, type| %> @@ -172,7 +172,7 @@ public struct <%= @grammar.prefix %>context_t /* Parser context data. */ /** Parse result value. */ -<% if @grammar.ast %> +<% if @grammar.tree %> void * parse_result; <% else %> <%= @grammar.prefix %>value_t parse_result; @@ -797,7 +797,7 @@ private struct reduce_t * reduce action. */ parser_state_id_t n_states; -<% if @grammar.ast %> +<% if @grammar.tree %> /** * Map of rule components to rule set child fields. @@ -805,7 +805,7 @@ private struct reduce_t immutable(ushort) * rule_set_node_field_index_map; /** - * Number of rule set AST node fields. + * Number of rule set tree node fields. */ ushort rule_set_node_field_array_size; @@ -847,9 +847,9 @@ private struct state_value_t /** Parser value from this state. */ <%= @grammar.prefix %>value_t pvalue; -<% if @grammar.ast %> - /** AST node. */ - void * ast_node; +<% if @grammar.tree %> + /** Tree node. */ + void * tree_node; <% end %> this(size_t state_id) @@ -865,7 +865,7 @@ private immutable shift_t[] parser_shift_table = [ <% end %> ]; -<% if @grammar.ast %> +<% if @grammar.tree %> <% @grammar.rules.each do |rule| %> <% unless rule.flat_rule_set_node_field_index_map? %> immutable ushort[<%= rule.rule_set_node_field_index_map.size %>] r_<%= rule.name.gsub("$", "_") %><%= rule.id %>_node_field_index_map = [<%= rule.rule_set_node_field_index_map.map {|v| v.to_s}.join(", ") %>]; @@ -880,14 +880,14 @@ private immutable reduce_t[] parser_reduce_table = [ <%= reduce[:token_id] %>u, /* Token: <%= reduce[:token] ? reduce[:token].name : "(any)" %> */ <%= reduce[:rule_id] %>u, /* Rule ID */ <%= reduce[:rule_set_id] %>u, /* Rule set ID (<%= reduce[:rule].rule_set.name %>) */ -<% if @grammar.ast %> +<% if @grammar.tree %> <%= reduce[:n_states] %>u, /* Number of states */ <% if reduce[:rule].flat_rule_set_node_field_index_map? %> null, /* No rule set node field index map (flat map) */ <% else %> &r_<%= reduce[:rule].name.gsub("$", "_") %><%= reduce[:rule].id %>_node_field_index_map[0], /* Rule set node field index map */ <% end %> - <%= reduce[:rule].rule_set.ast_fields.size %>, /* Number of AST fields */ + <%= reduce[:rule].rule_set.tree_fields.size %>, /* Number of tree fields */ <%= reduce[:propagate_optional_target] %>), /* Propagate optional target? */ <% else %> <%= reduce[:n_states] %>u), /* Number of states */ @@ -902,7 +902,7 @@ private immutable parser_state_t[] parser_state_table = [ <% end %> ]; -<% unless @grammar.ast %> +<% unless @grammar.tree %> /** * Execute user code associated with a parser rule. * @@ -1006,7 +1006,7 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star state_value_t[] statevalues = new state_value_t[](1); statevalues[0].state_id = start_state_id; size_t reduced_rule_set = INVALID_ID; -<% if @grammar.ast %> +<% if @grammar.tree %> void * reduced_parser_node; <% else %> <%= @grammar.prefix %>value_t reduced_parser_value; @@ -1033,8 +1033,8 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star if ((shift_state != INVALID_ID) && (token == TOKEN___EOF)) { /* Successful parse. */ -<% if @grammar.ast %> - context.parse_result = statevalues[$-1].ast_node; +<% if @grammar.tree %> + context.parse_result = statevalues[$-1].tree_node; <% else %> context.parse_result = statevalues[$-1].pvalue; <% end %> @@ -1048,9 +1048,9 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star if (reduced_rule_set == INVALID_ID) { /* We shifted a token, mark it consumed. */ -<% if @grammar.ast %> - <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %> * token_ast_node = new <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %>(token_info.position, token_info.end_position, token, token_info.pvalue); - statevalues[$-1].ast_node = token_ast_node; +<% if @grammar.tree %> + <%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> * token_tree_node = new <%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %>(token_info.position, token_info.end_position, token, token_info.pvalue); + statevalues[$-1].tree_node = token_tree_node; <% else %> statevalues[$-1].pvalue = token_info.pvalue; <% end %> @@ -1059,8 +1059,8 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star else { /* We shifted a RuleSet. */ -<% if @grammar.ast %> - statevalues[$-1].ast_node = reduced_parser_node; +<% if @grammar.tree %> + statevalues[$-1].tree_node = reduced_parser_node; <% else %> statevalues[$-1].pvalue = reduced_parser_value; <%= @grammar.prefix %>value_t new_parse_result; @@ -1075,16 +1075,16 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star if (reduce_index != INVALID_ID) { /* We have something to reduce. */ -<% if @grammar.ast %> +<% if @grammar.tree %> if (parser_reduce_table[reduce_index].propagate_optional_target) { - reduced_parser_node = statevalues[$ - 1].ast_node; + reduced_parser_node = statevalues[$ - 1].tree_node; } else if (parser_reduce_table[reduce_index].n_states > 0) { size_t n_fields = parser_reduce_table[reduce_index].rule_set_node_field_array_size; - size_t node_size = ASTNode.sizeof + n_fields * (void *).sizeof; - ASTNode * node = cast(ASTNode *)malloc(node_size); + size_t node_size = TreeNode.sizeof + n_fields * (void *).sizeof; + TreeNode * node = cast(TreeNode *)malloc(node_size); GC.addRange(node, node_size); node.position = <%= @grammar.prefix %>position_t.INVALID; node.end_position = <%= @grammar.prefix %>position_t.INVALID; @@ -1096,20 +1096,20 @@ private size_t parse_from(<%= @grammar.prefix %>context_t * context, size_t star { foreach (i; 0..parser_reduce_table[reduce_index].n_states) { - node.fields[i] = statevalues[$ - parser_reduce_table[reduce_index].n_states + i].ast_node; + node.fields[i] = statevalues[$ - parser_reduce_table[reduce_index].n_states + i].tree_node; } } else { foreach (i; 0..parser_reduce_table[reduce_index].n_states) { - node.fields[parser_reduce_table[reduce_index].rule_set_node_field_index_map[i]] = statevalues[$ - parser_reduce_table[reduce_index].n_states + i].ast_node; + node.fields[parser_reduce_table[reduce_index].rule_set_node_field_index_map[i]] = statevalues[$ - parser_reduce_table[reduce_index].n_states + i].tree_node; } } bool position_found = false; foreach (i; 0..n_fields) { - ASTNode * child = cast(ASTNode *)node.fields[i]; + TreeNode * child = cast(TreeNode *)node.fields[i]; if (child && child.position.valid) { if (!position_found) @@ -1171,15 +1171,15 @@ public size_t <%= @grammar.prefix %>parse_<%= start_rule %>(<%= @grammar.prefix * * @return Parse result value. */ -<% if @grammar.ast %> -public <%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context) +<% if @grammar.tree %> +public <%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context) { - return cast(<%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> *)context.parse_result; + return cast(<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> *)context.parse_result; } <% @grammar.start_rules.each_with_index do |start_rule, i| %> -public <%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context) +public <%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context) { - return cast(<%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> *)context.parse_result; + return cast(<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> *)context.parse_result; } <% end %> <% else %> diff --git a/assets/parser.h.erb b/assets/parser.h.erb index 2b8fc43..a4e022a 100644 --- a/assets/parser.h.erb +++ b/assets/parser.h.erb @@ -58,7 +58,7 @@ typedef struct /** User header code blocks. */ <%= @grammar.code_blocks.fetch("header", "") %> -<% if @grammar.ast %> +<% if @grammar.tree %> /** Parser values type. */ typedef <%= @grammar.ptype %> <%= @grammar.prefix %>value_t; <% else %> @@ -71,18 +71,18 @@ typedef union } <%= @grammar.prefix %>value_t; <% end %> -<% if @grammar.ast %> -/** AST node types. @{ */ -typedef struct <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %> +<% if @grammar.tree %> +/** Tree node types. @{ */ +typedef struct <%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %> { - <% # ASTNode fields must be present in the same order here. # %> + <% # TreeNode fields must be present in the same order here. # %> <%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t end_position; uint16_t n_fields; uint8_t is_token; <%= @grammar.prefix %>token_t token; <%= @grammar.prefix %>value_t pvalue; -} <%= @grammar.ast_prefix %>Token<%= @grammar.ast_suffix %>; +} <%= @grammar.tree_prefix %>Token<%= @grammar.tree_suffix %>; <% @parser.rule_sets.each do |name, rule_set| %> <% next if name.start_with?("$") %> @@ -93,14 +93,14 @@ struct <%= name %>; <% @parser.rule_sets.each do |name, rule_set| %> <% next if name.start_with?("$") %> <% next if rule_set.optional? %> -typedef struct <%= @grammar.ast_prefix %><%= name %><%= @grammar.ast_suffix %> +typedef struct <%= @grammar.tree_prefix %><%= name %><%= @grammar.tree_suffix %> { - <% # ASTNode fields must be present in the same order here. # %> + <% # TreeNode fields must be present in the same order here. # %> <%= @grammar.prefix %>position_t position; <%= @grammar.prefix %>position_t end_position; uint16_t n_fields; uint8_t is_token; -<% rule_set.ast_fields.each do |fields| %> +<% rule_set.tree_fields.each do |fields| %> union { <% fields.each do |field_name, type| %> @@ -108,7 +108,7 @@ typedef struct <%= @grammar.ast_prefix %><%= name %><%= @grammar.ast_suffix %> <% end %> }; <% end %> -} <%= @grammar.ast_prefix %><%= name %><%= @grammar.ast_suffix %>; +} <%= @grammar.tree_prefix %><%= name %><%= @grammar.tree_suffix %>; <% end %> /** @} */ @@ -161,7 +161,7 @@ typedef struct /* Parser context data. */ /** Parse result value. */ -<% if @grammar.ast %> +<% if @grammar.tree %> void * parse_result; <% else %> <%= @grammar.prefix %>value_t parse_result; @@ -193,10 +193,10 @@ size_t <%= @grammar.prefix %>parse(<%= @grammar.prefix %>context_t * context); size_t <%= @grammar.prefix %>parse_<%= start_rule %>(<%= @grammar.prefix %>context_t * context); <% end %> -<% if @grammar.ast %> -<%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context); +<% if @grammar.tree %> +<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context); <% @grammar.start_rules.each_with_index do |start_rule, i| %> -<%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context); +<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> * <%= @grammar.prefix %>result_<%= start_rule %>(<%= @grammar.prefix %>context_t * context); <% end %> <% else %> <%= start_rule_type[1] %> <%= @grammar.prefix %>result(<%= @grammar.prefix %>context_t * context); @@ -205,10 +205,10 @@ size_t <%= @grammar.prefix %>parse_<%= start_rule %>(<%= @grammar.prefix %>conte <% end %> <% end %> -<% if @grammar.ast %> -void <%= @grammar.prefix %>free_ast(<%= @grammar.ast_prefix %><%= @grammar.start_rules[0] %><%= @grammar.ast_suffix %> * ast); +<% if @grammar.tree %> +void <%= @grammar.prefix %>free_tree(<%= @grammar.tree_prefix %><%= @grammar.start_rules[0] %><%= @grammar.tree_suffix %> * tree); <% @grammar.start_rules.each_with_index do |start_rule, i| %> -void <%= @grammar.prefix %>free_ast_<%= start_rule %>(<%= @grammar.ast_prefix %><%= start_rule %><%= @grammar.ast_suffix %> * ast); +void <%= @grammar.prefix %>free_tree_<%= start_rule %>(<%= @grammar.tree_prefix %><%= start_rule %><%= @grammar.tree_suffix %> * tree); <% end %> <% end %> diff --git a/doc/user_guide.md b/doc/user_guide.md index adb4101..7cb5e30 100644 --- a/doc/user_guide.md +++ b/doc/user_guide.md @@ -14,7 +14,7 @@ Propane is a LALR Parser Generator (LPG) which: * supports UTF-8 lexer inputs * generates a table-driven shift/reduce parser to parse input in linear time * targets C, C++, or D language outputs - * optionally supports automatic full AST generation + * optionally supports automatic full parse tree generation * tracks input text start and end positions for all matched tokens/rules * is MIT-licensed * is distributable as a standalone Ruby script @@ -189,21 +189,21 @@ rule. Parser values for the rules or tokens in the rule pattern can be accessed positionally with tokens `$1`, `$2`, `$3`, etc... -Parser rule code blocks are not available in AST generation mode. -In AST generation mode, a full parse tree is automatically constructed in +Parser rule code blocks are not available in tree generation mode. +In tree generation mode, a full parse tree is automatically constructed in memory for user code to traverse after parsing is complete. -##> AST generation mode - the `ast` statement +##> Tree generation mode - the `tree` statement -To activate AST generation mode, place the `ast` statement in your grammar file: +To activate tree generation mode, place the `tree` statement in your grammar file: ``` -ast; +tree; ``` It is recommended to place this statement early in the grammar. -In AST generation mode various aspects of propane's behavior are changed: +In tree generation mode various aspects of propane's behavior are changed: * Only one `ptype` is allowed. * Parser user code blocks are not supported. @@ -214,10 +214,10 @@ In AST generation mode various aspects of propane's behavior are changed: with the `start` grammar statement, the name of the start struct will be given by the user-specified start rule instead of `Start`. -Example AST generation grammar: +Example tree generation grammar: ``` -ast; +tree; ptype int; @@ -284,23 +284,23 @@ assert_eq(22, itemsmore.item.pToken1.pvalue); assert(itemsmore.pItemsMore is null); ``` -## `ast_prefix` and `ast_suffix` statements +## `tree_prefix` and `tree_suffix` statements -In AST generation mode, structure types are defined and named based on the +In tree generation mode, structure types are defined and named based on the rules in the grammar. Additionally, a structure type called `Token` is generated to hold parsed token information. -These structure names can be modified by using the `ast_prefix` or `ast_suffix` +These structure names can be modified by using the `tree_prefix` or `tree_suffix` statements in the grammar file. The field names that point to instances of the structures are not affected by -the `ast_prefix` or `ast_suffix` values. +the `tree_prefix` or `tree_suffix` values. For example, if the following two lines were added to the example above: ``` -ast_prefix ABC; -ast_suffix XYZ; +tree_prefix ABC; +tree_suffix XYZ; ``` Then the types would be used as such instead: @@ -330,7 +330,7 @@ assert(itemsmore.pItem.pItem.pItem.pToken1 !is null); If user lexer code block allocates memory to store in a token node's `pvalue`, the `free_token_node` grammar statement can be used to specify the name of a -function which will be called during the `p_free_ast()` call to free the memory +function which will be called during the `p_free_tree()` call to free the memory associated with a token node. Example: @@ -342,7 +342,7 @@ static void free_token(Token * token) free(token->pvalue); } >> -ast; +tree; free_token_node free_token; ptype int *; token a << @@ -641,7 +641,7 @@ In this example: * a reduced `Values`'s parser value has a type of `Value[]`. * a reduced `KeyValue`'s parser value has a type of `Value[string]`. -When AST generation mode is active, the `ptype` functionality works differently. +When tree generation mode is active, the `ptype` functionality works differently. In this mode, only one `ptype` is used by the parser. Lexer user code blocks may assign a parse value to the generated `Token` node by assigning to `$$` within a lexer code block. @@ -700,8 +700,8 @@ A field can be immediately followed by a `?` character to signify that it is optional. A field can optionally be followed by a `:` and then a field alias name. If present, the field alias name is used to refer to the field value in user -code blocks, or if AST mode is active, the field alias name is used as the -field name in the generated AST node structure. +code blocks, or if tree generation mode is active, the field alias name is used +as the field name in the generated tree node structure. An optional and named field must use the format `field?:name`. Example: @@ -725,7 +725,7 @@ The `$$` symbol accesses the output parser value for this rule. The above examples demonstrate how the parser values for the rule components can be used to produce the parser value for the accepted rule. -Parser rule code blocks are not allowed and not used when AST generation mode +Parser rule code blocks are not allowed and not used when tree generation mode is active. ##> Specifying the parser start rule name - the `start` statement @@ -747,12 +747,12 @@ start Module ModuleItem Statement Expression; ``` When multiple start rules are specified, multiple `p_parse_*()` functions, -`p_result_*()`, and `p_free_ast_*()` functions (in AST mode) are generated. -A default `p_parse()`, `p_result()`, `p_free_ast()` are generated corresponding +`p_result_*()`, and `p_free_tree_*()` functions (in tree mode) are generated. +A default `p_parse()`, `p_result()`, `p_free_tree()` are generated corresponding to the first start rule. Additionally, each start rule causes the generation of another version of each of these functions, for example `p_parse_Statement()`, `p_result_Statement()`, -and `p_free_ast_Statement()`. +and `p_free_tree_Statement()`. ##> Specifying the parser module name - the `module` statement @@ -873,17 +873,17 @@ The `p_token_info_t` structure contains the following fields: * `token` (`p_token_t`) holds the token ID of the lexed token * `pvalue` (`p_value_t`) holds the parser value associated with the token. -### AST Node Types +### Tree Node Types -If AST generation mode is enabled, a structure type for each rule will be +If tree generation mode is enabled, a structure type for each rule will be generated. The name of the structure type is given by the name of the rule. -Additionally a structure type called `Token` is generated to represent an -AST node which refers to a raw parser token rather than a composite rule. +Additionally a structure type called `Token` is generated to represent a +tree node which refers to a raw parser token rather than a composite rule. -#### AST Node Fields +#### Tree Node Fields -All AST nodes have a `position` field specifying the text position of the +All tree nodes have a `position` field specifying the text position of the beginning of the matched token or rule, and an `end_position` field specifying the text position of the end of the matched token or rule. Each of these fields are instances of the `p_position_t` structure. @@ -902,7 +902,7 @@ A `Token` node has the following additional fields: * `pvalue` which specifies the parser value for the token. If a lexer user code block assigned to `$$`, the assigned value will be stored here. -AST node structures for rules contain generated fields based on the +Tree node structures for rules contain generated fields based on the right hand side components specified for all rules of a given name. In this example: @@ -925,10 +925,10 @@ The `Items` structure will have fields: * `pItemsMore` and `pItemsMore2` which point to the parsed `ItemsMore` structure. If a rule can be empty (for example in the second `Items` rule above), then -an instance of a pointer to that rule's generated AST node will be null if the +an instance of a pointer to that rule's generated tree node will be null if the parser matches the empty rule pattern. -The non-positional AST node field pointer will not be generated if there are +The non-positional tree node field pointer will not be generated if there are multiple positions in which an instance of the node it points to could be present. For example, in the below rules: @@ -948,7 +948,7 @@ If the first rule is matched, then `pOne1` and `pTwo2` will be non-null while If the second rule is matched instead, then the opposite would be the case. If a field alias is present in a rule definition, an additional field will be -generated in the AST node with the field alias name. +generated in the tree node with the field alias name. For example: ``` @@ -1079,8 +1079,8 @@ if (p_parse(&context) == P_SUCCESS) } ``` -If AST generation mode is active, then the `p_result()` function returns a -`Start *` pointing to the `Start` AST structure. +If tree generation mode is active, then the `p_result()` function returns a +`Start *` pointing to the `Start` tree node structure. When multiple start rules are specified, a separate result function is generated for each which returns the parse result for the corresponding rule. @@ -1171,29 +1171,29 @@ assert(code_point == 0x1F9E1u); assert(code_point_length == 4u); ``` -### `p_free_ast` +### `p_free_tree` -The `p_free_ast()` function can be used to free the memory used by the AST. +The `p_free_tree()` function can be used to free the memory used by the tree. It should be passed the same value that is returned by `p_result()`. -The `p_free_ast()` function is only available for C/C++ output targets. +The `p_free_tree()` function is only available for C/C++ output targets. Note that if any lexer user code block allocates memory to store in a token's `pvalue`, in order to properly free this memory a `free_token_node` function should be specified in the grammar file. If specified, the `free_token_node` function will be called during the -`p_free_ast()` process to allow user code to free any memory associated with +`p_free_tree()` process to allow user code to free any memory associated with a token node's `pvalue`. -When multiple start rules are specified, a separate `p_free_ast` function is -generated for each which frees the AST resulting from parsing the given rule. +When multiple start rules are specified, a separate `p_free_tree` function is +generated for each which frees the tree resulting from parsing the given rule. For example, if `Statement` is specified as a start rule: ``` -p_free_ast_Statement(statement_ast); +p_free_tree_Statement(statement_tree); ``` -In this case, Propane will free a `Statement` AST structure returned by the +In this case, Propane will free a `Statement` tree structure returned by the `p_parse_Statement(&context)` function. ##> Data diff --git a/extra/vim/syntax/propane.vim b/extra/vim/syntax/propane.vim index 09b4157..50ce5f1 100644 --- a/extra/vim/syntax/propane.vim +++ b/extra/vim/syntax/propane.vim @@ -20,7 +20,7 @@ syn match propaneOperator "->" syn match propaneFieldAlias ":[a-zA-Z0-9_]\+" contains=propaneFieldOperator syn match propaneFieldOperator ":" contained syn match propaneOperator "?" -syn keyword propaneKeyword ast ast_prefix ast_suffix drop module prefix ptype start token tokenid +syn keyword propaneKeyword drop free_token_node module prefix ptype start token tokenid tree tree_prefix tree_suffix syn region propaneRegex start="/" end="/" skip="\v\\\\|\\/" diff --git a/lib/propane/generator.rb b/lib/propane/generator.rb index 2fb3b26..bd2e41f 100644 --- a/lib/propane/generator.rb +++ b/lib/propane/generator.rb @@ -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" diff --git a/lib/propane/grammar.rb b/lib/propane/grammar.rb index 8572c28..bde2ed4 100644 --- a/lib/propane/grammar.rb +++ b/lib/propane/grammar.rb @@ -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 diff --git a/lib/propane/rule.rb b/lib/propane/rule.rb index 82bf860..fcd030a 100644 --- a/lib/propane/rule.rb +++ b/lib/propane/rule.rb @@ -36,7 +36,7 @@ class Propane # @return [Array] # 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. diff --git a/lib/propane/rule_set.rb b/lib/propane/rule_set.rb index ccdd5b0..8c4a019 100644 --- a/lib/propane/rule_set.rb +++ b/lib/propane/rule_set.rb @@ -4,8 +4,8 @@ class Propane class RuleSet # @return [Array] - # 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 diff --git a/spec/propane_spec.rb b/spec/propane_spec.rb index 3a100ff..e951839 100644 --- a/spec/propane_spec.rb +++ b/spec/propane_spec.rb @@ -245,20 +245,20 @@ EOF expect(results.status).to_not eq 0 end - it "errors when an alias is in different positions for different rules in a rule set when AST mode is enabled" do + it "errors when an alias is in different positions for different rules in a rule set when tree mode is enabled" do write_grammar < a:foo b; Start -> b b:foo; EOF results = run_propane(extra_args: %w[-w], capture: true) - expect(results.stderr).to match %r{Error: conflicting AST node field positions for alias `foo`} + expect(results.stderr).to match %r{Error: conflicting tree node field positions for alias `foo`} expect(results.status).to_not eq 0 end - it "does not error when an alias is in different positions for different rules in a rule set when AST mode is not enabled" do + it "does not error when an alias is in different positions for different rules in a rule set when tree mode is not enabled" do write_grammar < one; Two -> two; EOF run_propane(language: language) - compile("spec/test_ast.#{language}", language: language) + compile("spec/test_tree.#{language}", language: language) results = run_test(language: language) expect(results.stderr).to eq "" expect(results.status).to eq 0 end - it "supports AST node prefix and suffix" do + it "supports tree node prefix and suffix" do write_grammar < one; Two -> two; EOF run_propane(language: language) - compile("spec/test_ast_ps.#{language}", language: language) + compile("spec/test_tree_ps.#{language}", language: language) results = run_test(language: language) expect(results.stderr).to eq "" expect(results.status).to eq 0 @@ -1092,15 +1092,15 @@ EOF compile("spec/test_start_rule.#{language}", language: language) end - it "allows specifying a different start rule with AST generation" do + it "allows specifying a different start rule with tree generation" do write_grammar < hi; EOF run_propane(language: language) - compile("spec/test_start_rule_ast.#{language}", language: language) + compile("spec/test_start_rule_tree.#{language}", language: language) end it "allows marking a rule component as optional" do @@ -1167,10 +1167,10 @@ EOF ]) end - it "allows marking a rule component as optional in AST generation mode" do + it "allows marking a rule component as optional in tree generation mode" do if language == "d" write_grammar < d c; EOF else write_grammar < @@ -1202,16 +1202,16 @@ R -> d c; EOF end run_propane(language: language) - compile("spec/test_optional_rule_component_ast.#{language}", language: language) + compile("spec/test_optional_rule_component_tree.#{language}", language: language) results = run_test(language: language) expect(results.stderr).to eq "" expect(results.status).to eq 0 end - it "allows naming an optional rule component in AST generation mode" do + it "allows naming an optional rule component in tree generation mode" do if language == "d" write_grammar < d c; EOF else write_grammar < @@ -1243,15 +1243,15 @@ R -> d c; EOF end run_propane(language: language) - compile("spec/test_named_optional_rule_component_ast.#{language}", language: language) + compile("spec/test_named_optional_rule_component_tree.#{language}", language: language) results = run_test(language: language) expect(results.stderr).to eq "" expect(results.status).to eq 0 end - it "stores token and rule positions in AST nodes" do + it "stores token and rule positions in tree nodes" do write_grammar < bb; T -> c; EOF run_propane(language: language) - compile("spec/test_ast_token_positions.#{language}", language: language) + compile("spec/test_tree_token_positions.#{language}", language: language) results = run_test(language: language) expect(results.stderr).to eq "" expect(results.status).to eq 0 @@ -1271,7 +1271,7 @@ EOF it "stores invalid positions for empty rule matches" do write_grammar < a A; A -> bb? c?; EOF run_propane(language: language) - compile("spec/test_ast_invalid_positions.#{language}", language: language) + compile("spec/test_tree_invalid_positions.#{language}", language: language) results = run_test(language: language) expect(results.stderr).to eq "" expect(results.status).to eq 0 end - it "allows specifying field aliases in AST mode" do + it "allows specifying field aliases in tree mode" do write_grammar < b; T -> c; EOF run_propane(language: language) - compile("spec/test_ast_field_aliases.#{language}", language: language) + compile("spec/test_tree_field_aliases.#{language}", language: language) results = run_test(language: language) expect(results.stderr).to eq "" expect(results.status).to eq 0 end - it "aliases the correct field when multiple rules are in a rule set in AST mode" do + it "aliases the correct field when multiple rules are in a rule set in tree mode" do write_grammar < b; T -> c; EOF run_propane(language: language) - compile("spec/test_ast_field_aliases.#{language}", language: language) + compile("spec/test_tree_field_aliases.#{language}", language: language) results = run_test(language: language) expect(results.stderr).to eq "" expect(results.status).to eq 0 end - it "allows specifying field aliases when AST mode is not enabled" do + it "allows specifying field aliases when tree mode is not enabled" do if language == "d" write_grammar <> token b << $$ = 2; >> @@ -1475,14 +1475,14 @@ Bs -> b:b Bs:bs; start Start R Bs; EOF run_propane(language: language) - compile("spec/test_starting_rules_ast.#{language}", language: language) + compile("spec/test_starting_rules_tree.#{language}", language: language) results = run_test(language: language) expect(results.stderr).to eq "" expect(results.status).to eq 0 end if %w[c cpp].include?(language) - it "allows a user function to free token node memory in AST mode" do + it "allows a user function to free token node memory in tree mode" do write_grammar <pvalue); } >> -ast; +tree; free_token_node free_token; ptype int *; token a << @@ -1504,7 +1504,7 @@ token b << Start -> a:a b:b; EOF run_propane(language: language) - compile("spec/test_free_ast_token_node_memory.#{language}", language: language) + compile("spec/test_free_tree_token_node_memory.#{language}", language: language) results = run_test(language: language) expect(results.stderr).to eq "" expect(results.status).to eq 0 diff --git a/spec/test_free_ast_token_node_memory.c b/spec/test_free_tree_token_node_memory.c similarity index 94% rename from spec/test_free_ast_token_node_memory.c rename to spec/test_free_tree_token_node_memory.c index 7dd8fbf..041fc75 100644 --- a/spec/test_free_ast_token_node_memory.c +++ b/spec/test_free_tree_token_node_memory.c @@ -15,5 +15,5 @@ int main() assert(start->b != NULL); assert(*start->b->pvalue == 2); - p_free_ast(start); + p_free_tree(start); } diff --git a/spec/test_named_optional_rule_component_ast.c b/spec/test_named_optional_rule_component_tree.c similarity index 94% rename from spec/test_named_optional_rule_component_ast.c rename to spec/test_named_optional_rule_component_tree.c index 4244cf3..b3c45a4 100644 --- a/spec/test_named_optional_rule_component_ast.c +++ b/spec/test_named_optional_rule_component_tree.c @@ -17,7 +17,7 @@ int main() assert(start->pR == NULL); assert(start->r == NULL); - p_free_ast(start); + p_free_tree(start); input = "abcd"; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -33,7 +33,7 @@ int main() assert(start->pR == start->r); assert_eq(TOKEN_c, start->pR->pToken1->token); - p_free_ast(start); + p_free_tree(start); input = "bdc"; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -44,7 +44,7 @@ int main() assert(start->r != NULL); assert_eq(TOKEN_d, start->pR->pToken1->token); - p_free_ast(start); + p_free_tree(start); return 0; } diff --git a/spec/test_named_optional_rule_component_ast.d b/spec/test_named_optional_rule_component_tree.d similarity index 100% rename from spec/test_named_optional_rule_component_ast.d rename to spec/test_named_optional_rule_component_tree.d diff --git a/spec/test_optional_rule_component_ast.c b/spec/test_optional_rule_component_tree.c similarity index 94% rename from spec/test_optional_rule_component_ast.c rename to spec/test_optional_rule_component_tree.c index d88ea46..c709298 100644 --- a/spec/test_optional_rule_component_ast.c +++ b/spec/test_optional_rule_component_tree.c @@ -16,7 +16,7 @@ int main() assert(start->pR3 == NULL); assert(start->pR == NULL); - p_free_ast(start); + p_free_tree(start); input = "abcd"; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -30,7 +30,7 @@ int main() assert(start->pR == start->pR3); assert_eq(TOKEN_c, start->pR->pToken1->token); - p_free_ast(start); + p_free_tree(start); input = "bdc"; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -41,7 +41,7 @@ int main() assert(start->pR != NULL); assert_eq(TOKEN_d, start->pR->pToken1->token); - p_free_ast(start); + p_free_tree(start); return 0; } diff --git a/spec/test_optional_rule_component_ast.d b/spec/test_optional_rule_component_tree.d similarity index 100% rename from spec/test_optional_rule_component_ast.d rename to spec/test_optional_rule_component_tree.d diff --git a/spec/test_start_rule_ast.c b/spec/test_start_rule_tree.c similarity index 94% rename from spec/test_start_rule_ast.c rename to spec/test_start_rule_tree.c index d262143..025567e 100644 --- a/spec/test_start_rule_ast.c +++ b/spec/test_start_rule_tree.c @@ -13,7 +13,7 @@ int main() assert(top->pToken != NULL); assert_eq(TOKEN_hi, top->pToken->token); - p_free_ast(top); + p_free_tree(top); return 0; } diff --git a/spec/test_start_rule_ast.d b/spec/test_start_rule_tree.d similarity index 100% rename from spec/test_start_rule_ast.d rename to spec/test_start_rule_tree.d diff --git a/spec/test_starting_rules_ast.c b/spec/test_starting_rules_tree.c similarity index 93% rename from spec/test_starting_rules_ast.c rename to spec/test_starting_rules_tree.c index 8a2ca00..2b5403a 100644 --- a/spec/test_starting_rules_ast.c +++ b/spec/test_starting_rules_tree.c @@ -15,7 +15,7 @@ int main() assert_not_null(start->bs->bs->b); assert_not_null(start->bs->bs->bs->b); assert_not_null(start->bs->bs->bs->bs->b); - p_free_ast(start); + p_free_tree(start); p_context_init(&context, (uint8_t const *)input, strlen(input)); assert(p_parse_Bs(&context) == P_SUCCESS); @@ -24,14 +24,14 @@ int main() assert_not_null(bs->bs->b); assert_not_null(bs->bs->bs->b); assert_not_null(bs->bs->bs->bs->b); - p_free_ast_Bs(bs); + p_free_tree_Bs(bs); input = "c"; p_context_init(&context, (uint8_t const *)input, strlen(input)); assert(p_parse_R(&context) == P_SUCCESS); R * r = p_result_R(&context); assert_not_null(r->c); - p_free_ast_R(r); + p_free_tree_R(r); return 0; } diff --git a/spec/test_starting_rules_ast.d b/spec/test_starting_rules_tree.d similarity index 100% rename from spec/test_starting_rules_ast.d rename to spec/test_starting_rules_tree.d diff --git a/spec/test_ast.c b/spec/test_tree.c similarity index 96% rename from spec/test_ast.c rename to spec/test_tree.c index dd055bd..883030b 100644 --- a/spec/test_ast.c +++ b/spec/test_tree.c @@ -33,7 +33,7 @@ int main() assert_eq(22, itemsmore->pItem->pToken1->pvalue); assert(itemsmore->pItemsMore == NULL); - p_free_ast(start); + p_free_tree(start); input = ""; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -41,7 +41,7 @@ int main() start = p_result(&context); assert(start->pItems == NULL); - p_free_ast(start); + p_free_tree(start); input = "2 1"; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -55,7 +55,7 @@ int main() assert(start->pItems->pItem->pDual->pTwo2 == NULL); assert(start->pItems->pItem->pDual->pOne1 == NULL); - p_free_ast(start); + p_free_tree(start); return 0; } diff --git a/spec/test_ast.d b/spec/test_tree.d similarity index 100% rename from spec/test_ast.d rename to spec/test_tree.d diff --git a/spec/test_ast_field_aliases.c b/spec/test_tree_field_aliases.c similarity index 95% rename from spec/test_ast_field_aliases.c rename to spec/test_tree_field_aliases.c index fec19cc..0a3f51a 100644 --- a/spec/test_ast_field_aliases.c +++ b/spec/test_tree_field_aliases.c @@ -15,7 +15,7 @@ int main() assert_eq(TOKEN_b, start->second->pToken->token); assert_eq(TOKEN_c, start->third->pToken->token); - p_free_ast(start); + p_free_tree(start); return 0; } diff --git a/spec/test_ast_field_aliases.d b/spec/test_tree_field_aliases.d similarity index 100% rename from spec/test_ast_field_aliases.d rename to spec/test_tree_field_aliases.d diff --git a/spec/test_ast_invalid_positions.c b/spec/test_tree_invalid_positions.c similarity index 97% rename from spec/test_ast_invalid_positions.c rename to spec/test_tree_invalid_positions.c index 28beb7b..454bb3a 100644 --- a/spec/test_ast_invalid_positions.c +++ b/spec/test_tree_invalid_positions.c @@ -30,7 +30,7 @@ int main() assert_eq(3, start->end_position.row); assert_eq(8, start->end_position.col); - p_free_ast(start); + p_free_tree(start); input = "a\nbb"; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -56,7 +56,7 @@ int main() assert_eq(2, start->end_position.row); assert_eq(2, start->end_position.col); - p_free_ast(start); + p_free_tree(start); input = "a\nc\nc"; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -82,7 +82,7 @@ int main() assert_eq(3, start->end_position.row); assert_eq(1, start->end_position.col); - p_free_ast(start); + p_free_tree(start); input = "a"; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -104,7 +104,7 @@ int main() assert_eq(1, start->end_position.row); assert_eq(1, start->end_position.col); - p_free_ast(start); + p_free_tree(start); return 0; } diff --git a/spec/test_ast_invalid_positions.d b/spec/test_tree_invalid_positions.d similarity index 100% rename from spec/test_ast_invalid_positions.d rename to spec/test_tree_invalid_positions.d diff --git a/spec/test_ast_node_memory_remains.c b/spec/test_tree_node_memory_remains.c similarity index 99% rename from spec/test_ast_node_memory_remains.c rename to spec/test_tree_node_memory_remains.c index 78b4969..2c8a65f 100644 --- a/spec/test_ast_node_memory_remains.c +++ b/spec/test_tree_node_memory_remains.c @@ -412,7 +412,7 @@ int main(int argc, char * argv[]) } free(pfds); - p_free_ast(pmod); + p_free_tree(pmod); return 0; } diff --git a/spec/test_ast_node_memory_remains.d b/spec/test_tree_node_memory_remains.d similarity index 100% rename from spec/test_ast_node_memory_remains.d rename to spec/test_tree_node_memory_remains.d diff --git a/spec/test_ast_ps.c b/spec/test_tree_ps.c similarity index 96% rename from spec/test_ast_ps.c rename to spec/test_tree_ps.c index 516d164..62ec7cc 100644 --- a/spec/test_ast_ps.c +++ b/spec/test_tree_ps.c @@ -33,7 +33,7 @@ int main() assert_eq(22, itemsmore->pItem->pToken1->pvalue); assert(itemsmore->pItemsMore == NULL); - p_free_ast(start); + p_free_tree(start); input = ""; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -41,7 +41,7 @@ int main() start = p_result(&context); assert(start->pItems == NULL); - p_free_ast(start); + p_free_tree(start); input = "2 1"; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -55,7 +55,7 @@ int main() assert(start->pItems->pItem->pDual->pTwo2 == NULL); assert(start->pItems->pItem->pDual->pOne1 == NULL); - p_free_ast(start); + p_free_tree(start); return 0; } diff --git a/spec/test_ast_ps.d b/spec/test_tree_ps.d similarity index 100% rename from spec/test_ast_ps.d rename to spec/test_tree_ps.d diff --git a/spec/test_ast_token_positions.c b/spec/test_tree_token_positions.c similarity index 98% rename from spec/test_ast_token_positions.c rename to spec/test_tree_token_positions.c index 6354996..8d68776 100644 --- a/spec/test_ast_token_positions.c +++ b/spec/test_tree_token_positions.c @@ -43,7 +43,7 @@ int main() assert_eq(1, start->end_position.row); assert_eq(6, start->end_position.col); - p_free_ast(start); + p_free_tree(start); input = "\n\n bb\nc\ncc\n\n a"; p_context_init(&context, (uint8_t const *)input, strlen(input)); @@ -82,7 +82,7 @@ int main() assert_eq(7, start->end_position.row); assert_eq(6, start->end_position.col); - p_free_ast(start); + p_free_tree(start); return 0; } diff --git a/spec/test_ast_token_positions.d b/spec/test_tree_token_positions.d similarity index 100% rename from spec/test_ast_token_positions.d rename to spec/test_tree_token_positions.d diff --git a/spec/ast_node_memory_remains.c.propane b/spec/tree_node_memory_remains.c.propane similarity index 99% rename from spec/ast_node_memory_remains.c.propane rename to spec/tree_node_memory_remains.c.propane index 120ba3b..0e02fd9 100644 --- a/spec/ast_node_memory_remains.c.propane +++ b/spec/tree_node_memory_remains.c.propane @@ -1,5 +1,5 @@ -ast; -ast_prefix P; +tree; +tree_prefix P; <
diff --git a/spec/ast_node_memory_remains.d.propane b/spec/tree_node_memory_remains.d.propane similarity index 99% rename from spec/ast_node_memory_remains.d.propane rename to spec/tree_node_memory_remains.d.propane index e471a15..7bd9643 100644 --- a/spec/ast_node_memory_remains.d.propane +++ b/spec/tree_node_memory_remains.d.propane @@ -1,5 +1,5 @@ -ast; -ast_prefix P; +tree; +tree_prefix P; << import std.bigint;