From 50d6f7cd648b5ade914ebf763cfe57dc2876c1ae Mon Sep 17 00:00:00 2001 From: Miguel Lechon Date: Tue, 16 Feb 2021 19:35:24 +0100 Subject: [PATCH] [grammar test] Labeled nodes and tag parameters. --- tests/grammar.c | 114 ++++++++++++++++++++++++++--------------------- tests/grammar.md | 25 ++++++----- 2 files changed, 75 insertions(+), 64 deletions(-) diff --git a/tests/grammar.c b/tests/grammar.c index 6e12ced..64244d3 100644 --- a/tests/grammar.c +++ b/tests/grammar.c @@ -137,7 +137,7 @@ static void PrintRule(MD_Node *rule) typedef enum AllowedOperationFlags AllowedOperationFlags; enum AllowedOperationFlags { - AllowedOperationFlag_Leaf = 1<<0, + AllowedOperationFlag_Fill = 1<<0, AllowedOperationFlag_Tag = 1<<1, }; @@ -160,6 +160,45 @@ static void ExpandRule(MD_Node *rule, MD_String8List *out_strings, MD_Node *cur_ if(expand) { + MD_Node *node_to_tag = 0; + MD_b32 is_markup = 0; + AllowedOperationFlags new_flags = 0; + for(MD_EachNode(tag_node, rule_element->first_tag)){ + if(MD_StringMatch(tag_node->string, MD_S8Lit("child"), 0)) + { + cur_node = NewChild(cur_node); + allowed &= ~AllowedOperationFlag_Tag; // NOTE(mal): Tag parameters are not tags + } + else if(MD_StringMatch(tag_node->string, MD_S8Lit("sibling"), 0)) + { + cur_node = NewChild(cur_node->parent); + } + else if(MD_StringMatch(tag_node->string, MD_S8Lit("fill"), 0)) + { + new_flags |= AllowedOperationFlag_Fill; + } + else if(MD_StringMatch(tag_node->string, MD_S8Lit("tag"), 0)) + { + new_flags |= AllowedOperationFlag_Tag; + node_to_tag = cur_node; + cur_node = NewChild(0); + cur_node->kind = MD_NodeKind_Tag; + } + else if(MD_StringMatch(tag_node->string, MD_S8Lit(OPTIONAL_TAG), 0)) + { + } + else if(MD_StringMatch(tag_node->string, MD_S8Lit("markup"), 0)) + { + is_markup = 1; + } + else + { + MD_Assert(!"Not implemented"); + } + } + + allowed |= new_flags; + MD_b32 has_children = !MD_NodeIsNil(rule_element->first_child); if(has_children) { @@ -186,18 +225,10 @@ static void ExpandRule(MD_Node *rule, MD_String8List *out_strings, MD_Node *cur_ MD_String8 character = MD_PushStringF("%c", c); MD_PushStringToList(out_strings, character); - if(allowed & AllowedOperationFlag_Leaf) - { - Extend(&cur_node->whole_string, c); - if(!MD_NodeHasTag(rule_element, MD_S8Lit("delimiter"))) - { - Extend(&cur_node->string, c); - } - } - else if(allowed & AllowedOperationFlag_Tag) + if(allowed & (AllowedOperationFlag_Fill|AllowedOperationFlag_Tag)) { Extend(&cur_node->whole_string, c); - if(c != '@') + if(!is_markup) { Extend(&cur_node->string, c); } @@ -205,47 +236,20 @@ static void ExpandRule(MD_Node *rule, MD_String8List *out_strings, MD_Node *cur_ } else // NOTE(mal): Non-terminal production { - MD_Node *node_to_tag = 0; - if(MD_NodeHasTag(rule_element, MD_S8Lit("child"))) - { - cur_node = NewChild(cur_node); - } - else if(MD_NodeHasTag(rule_element, MD_S8Lit("sibling"))) - { - cur_node = NewChild(cur_node->parent); - } - else if(MD_NodeHasTag(rule_element, MD_S8Lit("leaf"))) - { - allowed |= AllowedOperationFlag_Leaf; - } - else if(MD_NodeHasTag(rule_element, MD_S8Lit("tag"))) - { - allowed |= AllowedOperationFlag_Tag; - node_to_tag = cur_node; - cur_node = NewChild(0); - cur_node->kind = MD_NodeKind_Tag; - } MD_Node * production = MD_NodeTable_Lookup(globals.production_table, rule_element->string)->node; MD_Assert(production); - ExpandProduction(production, out_strings, cur_node, allowed); - if(node_to_tag) - { - MD_PushTag(node_to_tag, cur_node); - cur_node = node_to_tag; - } - - if(MD_NodeHasTag(rule_element, MD_S8Lit("leaf"))) - { - allowed &= ~AllowedOperationFlag_Leaf; - } - else if(MD_NodeHasTag(rule_element, MD_S8Lit("tag"))) - { - allowed &= ~AllowedOperationFlag_Tag; - } } } + + if(node_to_tag) + { + MD_PushTag(node_to_tag, cur_node); + cur_node = node_to_tag; + } + + allowed &= ~new_flags; } } } @@ -411,11 +415,15 @@ int main(int argument_count, char **arguments) } // NOTE(mal): Check for root production - MD_Node* file_production = MD_NodeTable_Lookup(globals.production_table, MD_S8Lit("file"))->node; - if(!file_production) + MD_Node* file_production = 0; { - fprintf(stderr, "Error: Grammar file does not specify \"file\" production\n"); - goto error; + MD_NodeTableSlot *file_production_slot = MD_NodeTable_Lookup(globals.production_table, MD_S8Lit("file")); + if(!file_production_slot) + { + fprintf(stderr, "Error: Grammar file does not specify \"file\" production\n"); + goto error; + } + file_production = file_production_slot->node; } // NOTE(mal): Check that all branches lead to terminal nodes @@ -442,9 +450,12 @@ int main(int argument_count, char **arguments) MD_Node* node = MD_NodeTable_Lookup(globals.production_table, MD_S8Lit("file"))->node; MD_u32 test_count = 1000; - for(int i = 0; i < test_count; ++i){ + for(int i = 0; i < test_count; ++i) + { MD_String8List expanded_list = {0}; + //if(i == 25) BP; + // NOTE(mal): Generate a random MD file MD_Node *file_control_node = NewChild(0); file_control_node->kind = MD_NodeKind_File; @@ -463,7 +474,6 @@ int main(int argument_count, char **arguments) MD_OutputTree(stdout, file_node); printf("Grammar:\n"); MD_OutputTree(stdout, file_control_node); printf("\n"); - return -1; } } diff --git a/tests/grammar.md b/tests/grammar.md index 467da71..3ebc8c2 100644 --- a/tests/grammar.md +++ b/tests/grammar.md @@ -1,20 +1,21 @@ /* MetaDesk grammar with semantic annotations * - * Each line represents a BNF-esque production of the form: + * Each line represents a BNF-esque production: * symbol : rule_1 | ... | rule_n * - Pipe signs indicate mutually exclusive alternatives * - Square quotes denote optional rules * - Character literals are terminal productions - * - Tags indicate which way the productions attach to the generated tree (@child, @sibling, @leaf, @tag) - * and miscellaneous semantics (@delimiter) + * - Tags indicate which way the productions attach to the generated tree (@child, @sibling, @fill, @tag) + * and miscellaneous semantics (@markup) */ file : [@child set_list] set_list : tagged_named_set [' ' @sibling set_list] tagged_named_set: { [tag_list] set } -tag_list : @tag tag ' ' [tag_list] -tag : '@' identifier // TODO(mal): tag parameters -set : @leaf leaf | '{' [@child set_list] '}' + // TODO(mal): Accept other open/close tokens +set : @fill leaf | @fill identifier ':' @child @fill leaf | [@fill identifier ':'] '{' [@child set_list] '}' +tag_list : '@' @tag tag ' ' [tag_list] +tag : identifier [@markup '(' [@child set_list] @markup ')'] leaf : identifier | integer_literal | char_literal | string_literal // TODO(mal): Also symbol_label identifier : alpha [alphanumeric] // TODO(mal): I think we should allow leading underscores alphanumeric : alpha [alphanumeric] | digit [alphanumeric] | '_' [alphanumeric] @@ -22,7 +23,7 @@ alphanumeric : alpha [alphanumeric] | digit [alphanumeric] | '_' [alphanumeri integer_literal : { ['-'] natural_literal } natural_literal : digit [natural_literal] -char_literal : @delimiter '\'' [char_literal_items] @delimiter '\'' +char_literal : @markup '\'' [char_literal_items] @markup '\'' char_literal_items : char_literal_item [char_literal_items] char_literal_item : ascii_no_backslash_no_quotes | '"' | '\\' ascii ascii : ascii_no_backslash_no_quotes | '\'' | '"' | '\\' @@ -31,7 +32,7 @@ symbol_no_backslash_no_quotes : symbol_no_backslash_no_quotes_1 | symbol_no_ba symbol_no_backslash_no_quotes_1 : '!'|'#'|'$'|'%'|'&'|'('|')'|'*'|'+'|','|'-'|'.'|'/'|':'|';' symbol_no_backslash_no_quotes_2 : '<'|'='|'>'|'?'|'@'|'['|']'|'^'|'_'|'`'|'{'|'|'|'}'|'~' -string_literal : @delimiter '"' [string_literal_items] @delimiter '"' +string_literal : @markup '"' [string_literal_items] @markup '"' string_literal_items : string_literal_item [string_literal_items] string_literal_item : ascii_no_backslash_no_quotes | '\'' | '\\' ascii @@ -60,16 +61,16 @@ symbol_colon : ':' /* - // NOTE(mal): I think this one should work too, but MD only delimits top level constructs with newlines + // NOTE(mal): I think this one should work too, but MD only allows newlines as top-level construct separators file : [@child set_list] set_list : set [',' @sibling set_list] - set : @leaf element | '{' [@child set_list] '}' + set : @fill element | '{' [@child set_list] '}' element : 'A' - // NOTE(mal): This is the simples grammar that works + // NOTE(mal): This is the simplest grammar that works file : [@child set_list] set_list : set ['\n' @sibling set_list] - set : @leaf element | '{' [@child set_list] '}' + set : @fill element | '{' [@child set_list] '}' element : 'A' */