From 93f27666db09107561c2500c7b5e2047dbbc72fb Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Wed, 10 Jul 2013 23:45:09 -0700 Subject: [PATCH] More work --- parse_tree.cpp | 34 +++++-- parse_tree.h | 263 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 289 insertions(+), 8 deletions(-) diff --git a/parse_tree.cpp b/parse_tree.cpp index d3e14fd2f..d812c67ed 100644 --- a/parse_tree.cpp +++ b/parse_tree.cpp @@ -2,6 +2,7 @@ #include "tokenizer.h" #include +using namespace parse_symbols; wcstring parse_error_t::describe(const wcstring &src) const { @@ -355,6 +356,25 @@ class parse_ll_t if (tok2.type != token_type_invalid) symbol_stack.push_back(tok2); if (tok1.type != token_type_invalid) symbol_stack.push_back(tok1); } + + template + inline void symbol_stack_pop_push2() + { + symbol_stack_pop_push(T::t0::get_token(), T::t1::get_token(), T::t2::get_token(), T::t3::get_token(), T::t4::get_token()); + } + + template + inline void symbol_stack_pop_push_production(int which) + { + switch (which) + { + case 0: symbol_stack_pop_push2(); break; + case 1: symbol_stack_pop_push2(); break; + case 2: symbol_stack_pop_push2(); break; + case 3: symbol_stack_pop_push2(); break; + case 4: symbol_stack_pop_push2(); break; + } + } }; void parse_ll_t::dump_stack(void) const @@ -418,12 +438,12 @@ void parse_ll_t::accept_token_job_list(parse_token_t token) case parse_keyword_end: case parse_keyword_else: // End this job list - symbol_stack_pop_push(); + symbol_stack_pop_push_production(0); break; default: // Normal string - symbol_stack_pop_push(symbol_job, symbol_job_list); + symbol_stack_pop_push_production(1); break; } break; @@ -431,16 +451,17 @@ void parse_ll_t::accept_token_job_list(parse_token_t token) case parse_token_type_pipe: case parse_token_type_redirection: case parse_token_background: - symbol_stack_pop_push(symbol_job, symbol_job_list); + symbol_stack_pop_push_production(1); break; case parse_token_type_end: - symbol_stack_pop_push(parse_token_type_end, symbol_job_list); + // Empty line + symbol_stack_pop_push_production(2); break; case parse_token_type_terminate: // no more commands, just transition to empty - symbol_stack_pop_push(); + symbol_stack_pop_push_production(0); break; default: @@ -452,7 +473,8 @@ void parse_ll_t::accept_token_job_list(parse_token_t token) void parse_ll_t::accept_token_job(parse_token_t token) { PARSE_ASSERT(stack_top_type() == symbol_job); - symbol_stack_pop_push(symbol_statement, symbol_job_continuation); + //symbol_stack_pop_push(symbol_statement, symbol_job_continuation); + symbol_stack_pop_push2(); } void parse_ll_t::accept_token_job_continuation(parse_token_t token) diff --git a/parse_tree.h b/parse_tree.h index 525480f3a..9e3f087e0 100644 --- a/parse_tree.h +++ b/parse_tree.h @@ -46,7 +46,6 @@ class parse_t bool parse(const wcstring &str, parse_node_tree_t *output, parse_error_list_t *errors); }; - enum parse_token_type_t { token_type_invalid, @@ -155,6 +154,266 @@ class parse_node_tree_t : public std::vector { }; +namespace parse_symbols +{ + + #define SYMBOL(x) static inline parse_token_type_t get_token() { return x; } + + /* Placeholder */ + struct none + { + SYMBOL(token_type_invalid); + }; + + struct EMPTY + { + typedef none t0; + typedef none t1; + typedef none t2; + typedef none t3; + typedef none t4; + typedef none t5; + }; + + template + struct Seq + { + typedef T0 t0; + typedef T1 t1; + typedef T2 t2; + typedef T3 t3; + typedef T4 t4; + typedef T5 t5; + }; + + template + struct OR + { + typedef P0 p0; + typedef P1 p1; + typedef P2 p2; + typedef P3 p3; + typedef P4 p4; + typedef P5 p5; + }; + + template + struct Token + { + SYMBOL(WHICH); + }; + + template + struct Keyword + { + static inline parse_keyword_t get_token() { return WHICH; } + }; + + struct job; + struct statement; + struct job_continuation; + struct boolean_statement; + struct block_statement; + struct if_statement; + struct if_clause; + struct else_clause; + struct else_continuation; + struct switch_statement; + struct decorated_statement; + struct else_clause; + struct else_continuation; + struct switch_statement; + struct case_item_list; + struct case_item; + struct argument_list_nonempty; + struct argument_list; + struct block_statement; + struct block_header; + struct for_header; + struct while_header; + struct begin_header; + struct function_header; + struct boolean_statement; + struct decorated_statement; + struct plain_statement; + struct arguments_or_redirections_list; + struct argument_or_redirection; + struct redirection; + struct statement_terminator; + + /* A job_list is a list of jobs, separated by semicolons or newlines */ + struct job_list : OR< + EMPTY, + Seq, + Seq, job_list> + > + { + SYMBOL(symbol_job_list) + }; + + /* A job is a non-empty list of statements, separated by pipes. (Non-empty is useful for cases like if statements, where we require a command). To represent "non-empty", we require a statement, followed by a possibly empty job_continuation */ + struct job : Seq + { + SYMBOL(symbol_job); + }; + + struct job_continuation : OR< + EMPTY, + Seq, statement, job_continuation> + > + { + SYMBOL(symbol_job_continuation); + }; + + /* A statement is a normal command, or an if / while / and etc */ + struct statement : OR< + boolean_statement, + block_statement, + if_statement, + switch_statement, + decorated_statement + > + { + SYMBOL(symbol_statement); + }; + + struct if_statement : Seq > + { + SYMBOL(symbol_if_statement); + }; + + struct if_clause : Seq, job, statement_terminator, job_list> + { + SYMBOL(symbol_if_clause); + }; + + struct else_clause : OR< + EMPTY, + Keyword, else_continuation + > + { + SYMBOL(symbol_else_clause); + }; + + struct else_continuation : OR< + Seq, + Seq + > + { + SYMBOL(symbol_else_continuation); + }; + + struct switch_statement : Seq, Token, statement_terminator, case_item_list, Keyword + > + { + SYMBOL(symbol_switch_statement); + }; + + struct case_item_list : OR + < + EMPTY, + case_item, case_item_list + > + { + SYMBOL(symbol_case_item_list); + }; + + struct case_item : Seq, argument_list, statement_terminator, job_list> + { + SYMBOL(symbol_case_item); + }; + + struct argument_list_nonempty : Seq, argument_list> + { + SYMBOL(symbol_argument_list_nonempty); + }; + + struct argument_list : OR + { + SYMBOL(symbol_argument_list); + }; + + struct block_statement : Seq, arguments_or_redirections_list> + { + SYMBOL(symbol_block_statement); + }; + + struct block_header : OR + { + SYMBOL(symbol_block_header); + }; + + struct for_header : Seq, Token, Keyword, arguments_or_redirections_list> + { + SYMBOL(symbol_for_header); + }; + + struct while_header : Seq, statement> + { + SYMBOL(symbol_while_header); + }; + + struct begin_header : Keyword + { + SYMBOL(symbol_begin_header); + }; + + struct function_header : Keyword + { + SYMBOL(symbol_function_header); + }; + + /* A boolean statement is AND or OR or NOT */ + struct boolean_statement : OR< + Seq, statement>, + Seq, statement>, + Seq, statement> + > + { + SYMBOL(symbol_boolean_statement); + }; + + /* A decorated_statement is a command with a list of arguments_or_redirections, possibly with "builtin" or "command" */ + struct decorated_statement : OR< + Seq, plain_statement>, + Seq, plain_statement>, + plain_statement + > + { + SYMBOL(symbol_decorated_statement); + }; + + struct plain_statement : Seq, arguments_or_redirections_list> + { + SYMBOL(symbol_plain_statement); + }; + + struct arguments_or_redirections_list : OR< + EMPTY, + Seq > + { + SYMBOL(symbol_arguments_or_redirections_list); + }; + + struct argument_or_redirection : OR< + Token, + redirection + > + { + SYMBOL(symbol_argument_or_redirection); + }; + + struct redirection : Token + { + SYMBOL(parse_token_type_redirection); + }; + + struct statement_terminator : Token + { + SYMBOL(parse_token_type_end); + }; +} + /* Fish grammar: @@ -205,7 +464,7 @@ class parse_node_tree_t : public std::vector # A decorated_statement is a command with a list of arguments_or_redirections, possibly with "builtin" or "command" decorated_statement = COMMAND plain_statement | BUILTIN plain_statement | plain_statement - plain_statement = command arguments_or_redirections_list + plain_statement = COMMAND arguments_or_redirections_list arguments_or_redirections_list = | argument_or_redirection arguments_or_redirections_list