If statements parse

This commit is contained in:
ridiculousfish 2013-06-27 15:12:27 -07:00
parent 66af0c1a53
commit eba5b0e4c5
3 changed files with 130 additions and 49 deletions

View file

@ -229,29 +229,6 @@ class parse_exec_t
pop();
}
void assemble_if_header(exec_node_t &exec_node, const parse_node_t &header)
{
PARSE_ASSERT(header.type == symbol_if_header);
PARSE_ASSERT(&header == &parse_tree.at(exec_node.parse_node_idx));
PARSE_ASSERT(exec_node.body_parse_node_idx != NODE_OFFSET_INVALID);
if_header_t if_header;
if_header.body = exec_node.body_parse_node_idx;
// We may hit this on enter or exit
if (! exec_node.visited)
{
// Entry. Don't pop the header - just push the job. We'll pop it on exit.
exec_node.visited = true;
visitor->enter_if_header(if_header);
push(header.child_offset(1));
}
else
{
// Exit. Pop it.
visitor->exit_if_header(if_header);
pop();
}
}
void enter_parse_node(size_t idx);
void run_top_node(void);
@ -367,11 +344,11 @@ void parse_exec_t::run_top_node()
break;
}
case symbol_if_header:
case symbol_if_statement:
{
PARSE_ASSERT(parse_node.child_count == 2);
assemble_if_header(exec_node, parse_node);
break;
PARSE_ASSERT(parse_node.child_count == 3);
}
case symbol_decorated_statement:

View file

@ -51,11 +51,16 @@ wcstring token_type_description(parse_token_type_t type)
case symbol_statement: return L"statement";
case symbol_block_statement: return L"block_statement";
case symbol_block_header: return L"block_header";
case symbol_if_header: return L"if_header";
case symbol_for_header: return L"for_header";
case symbol_while_header: return L"while_header";
case symbol_begin_header: return L"begin_header";
case symbol_function_header: return L"function_header";
case symbol_if_statement: return L"if_statement";
case symbol_if_clause: return L"if_clause";
case symbol_else_clause: return L"else_clause";
case symbol_else_continuation: return L"else_continuation";
case symbol_boolean_statement: return L"boolean_statement";
case symbol_decorated_statement: return L"decorated_statement";
case symbol_plain_statement: return L"plain_statement";
@ -213,6 +218,17 @@ struct parse_stack_element_t
parse_stack_element_t(parse_keyword_t k) : type(parse_token_type_string), keyword(k), node_idx(-1)
{
}
wcstring describe(void) const
{
wcstring result = token_type_description(type);
if (keyword != parse_keyword_none)
{
append_format(result, L" <%ls>", keyword_description(keyword).c_str());
}
return result;
}
};
class parse_ll_t
@ -244,7 +260,8 @@ class parse_ll_t
void accept_token_job_continuation(parse_token_t token);
void accept_token_statement(parse_token_t token);
void accept_token_block_header(parse_token_t token);
void accept_token_if_header(parse_token_t token);
void accept_token_else_clause(parse_token_t token);
void accept_token_else_continuation(parse_token_t token);
void accept_token_boolean_statement(parse_token_t token);
void accept_token_decorated_statement(parse_token_t token);
void accept_token_plain_statement(parse_token_t token);
@ -257,6 +274,8 @@ class parse_ll_t
void parse_error(const wchar_t *expected, parse_token_t token);
void append_error_callout(wcstring &error_message, parse_token_t token);
void dump_stack(void) const;
// Get the node corresponding to the top element of the stack
parse_node_t &node_for_top_symbol()
{
@ -294,11 +313,11 @@ class parse_ll_t
if (1)
{
fprintf(stderr, "Pop %ls\n", token_type_description(symbol_stack.back().type).c_str());
if (tok5.type != token_type_invalid) fprintf(stderr, "Push %ls\n", token_type_description(tok5.type).c_str());
if (tok4.type != token_type_invalid) fprintf(stderr, "Push %ls\n", token_type_description(tok4.type).c_str());
if (tok3.type != token_type_invalid) fprintf(stderr, "Push %ls\n", token_type_description(tok3.type).c_str());
if (tok2.type != token_type_invalid) fprintf(stderr, "Push %ls\n", token_type_description(tok2.type).c_str());
if (tok1.type != token_type_invalid) fprintf(stderr, "Push %ls\n", token_type_description(tok1.type).c_str());
if (tok5.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok5.describe().c_str());
if (tok4.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok4.describe().c_str());
if (tok3.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok3.describe().c_str());
if (tok2.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok2.describe().c_str());
if (tok1.type != token_type_invalid) fprintf(stderr, "Push %ls\n", tok1.describe().c_str());
}
// Get the node for the top symbol and tell it about its children
@ -329,9 +348,41 @@ class parse_ll_t
}
};
void parse_ll_t::dump_stack(void) const
{
// Walk backwards from the top, looking for parents
wcstring_list_t lines;
if (symbol_stack.empty())
{
lines.push_back(L"(empty)");
}
else
{
node_offset_t child = symbol_stack.back().node_idx;
node_offset_t cursor = child;
lines.push_back(nodes.at(cursor).describe());
while (cursor--)
{
const parse_node_t &node = nodes.at(cursor);
if (node.child_start <= child && node.child_start + node.child_count > child)
{
lines.push_back(node.describe());
child = cursor;
}
}
}
fprintf(stderr, "Stack dump (%lu elements):\n", symbol_stack.size());
for (size_t idx = 0; idx < lines.size(); idx++)
{
fprintf(stderr, " %ls\n", lines.at(idx).c_str());
}
}
void parse_ll_t::token_unhandled(parse_token_t token, const char *function)
{
fprintf(stderr, "Unhandled token with type %ls in function %s\n", token_type_description(token.type).c_str(), function);
this->dump_stack();
PARSER_DIE();
}
@ -424,7 +475,6 @@ void parse_ll_t::accept_token_statement(parse_token_t token)
symbol_stack_pop_push(symbol_boolean_statement);
break;
case parse_keyword_if:
case parse_keyword_for:
case parse_keyword_while:
case parse_keyword_function:
@ -432,6 +482,10 @@ void parse_ll_t::accept_token_statement(parse_token_t token)
symbol_stack_pop_push(symbol_block_statement);
break;
case parse_keyword_if:
symbol_stack_pop_push(symbol_if_statement);
break;
case parse_keyword_else:
case parse_keyword_switch:
symbol_stack_pop_push(symbol_block_statement);
@ -475,10 +529,6 @@ void parse_ll_t::accept_token_block_header(parse_token_t token)
case parse_token_type_string:
switch (token.keyword)
{
case parse_keyword_if:
symbol_stack_pop_push(symbol_if_header);
break;
case parse_keyword_else:
PARSER_DIE(); //todo
break;
@ -513,6 +563,36 @@ void parse_ll_t::accept_token_block_header(parse_token_t token)
}
}
void parse_ll_t::accept_token_else_clause(parse_token_t token)
{
PARSE_ASSERT(stack_top_type() == symbol_else_clause);
switch (token.keyword)
{
case parse_keyword_else:
symbol_stack_pop_push(parse_keyword_else, symbol_else_continuation);
break;
default:
symbol_stack_pop_push();
break;
}
}
void parse_ll_t::accept_token_else_continuation(parse_token_t token)
{
PARSE_ASSERT(stack_top_type() == symbol_else_continuation);
switch (token.keyword)
{
case parse_keyword_if:
symbol_stack_pop_push(symbol_if_clause, symbol_else_clause);
break;
default:
symbol_stack_pop_push(parse_token_type_end, symbol_job_list);
break;
}
}
void parse_ll_t::accept_token_boolean_statement(parse_token_t token)
{
PARSE_ASSERT(stack_top_type() == symbol_boolean_statement);
@ -705,6 +785,22 @@ void parse_ll_t::accept_token(parse_token_t token, const wcstring &src)
accept_token_statement(token);
break;
case symbol_if_statement:
symbol_stack_pop_push(symbol_if_clause, symbol_else_clause, parse_keyword_end);
break;
case symbol_if_clause:
symbol_stack_pop_push(parse_keyword_if, symbol_job, parse_token_type_end, symbol_job_list);
break;
case symbol_else_clause:
accept_token_else_clause(token);
break;
case symbol_else_continuation:
accept_token_else_continuation(token);
break;
case symbol_block_statement:
symbol_stack_pop_push(symbol_block_header, parse_token_type_end, symbol_job_list, parse_keyword_end, symbol_arguments_or_redirections_list);
break;
@ -713,10 +809,6 @@ void parse_ll_t::accept_token(parse_token_t token, const wcstring &src)
accept_token_block_header(token);
break;
case symbol_if_header:
symbol_stack_pop_push(parse_keyword_if, symbol_job);
break;
case symbol_for_header:
symbol_stack_pop_push(parse_keyword_for, parse_token_type_string, parse_keyword_in, symbol_arguments_or_redirections_list, parse_token_type_end);
break;

View file

@ -15,7 +15,7 @@
#include <vector>
#define PARSE_ASSERT(a) assert(a)
#define PARSER_DIE() assert(0)
#define PARSER_DIE() exit_without_destructors(-1)
class parse_node_t;
class parse_node_tree_t;
@ -58,11 +58,16 @@ enum parse_token_type_t
symbol_statement,
symbol_block_statement,
symbol_block_header,
symbol_if_header,
symbol_for_header,
symbol_while_header,
symbol_begin_header,
symbol_function_header,
symbol_if_statement,
symbol_if_clause,
symbol_else_clause,
symbol_else_continuation,
symbol_boolean_statement,
symbol_decorated_statement,
symbol_plain_statement,
@ -159,18 +164,25 @@ class parse_node_tree_t : public std::vector<parse_node_t>
# A statement is a normal command, or an if / while / and etc
statement = boolean_statement | block_statement | decorated_statement
statement = boolean_statement | block_statement | if_statement | decorated_statement
# A block is a conditional, loop, or begin/end
if_statement = if_clause else_clause <END>
if_clause = <IF> job STATEMENT_TERMINATOR job_list
else_clause = <empty> |
<ELSE> else_continuation
else_continuation = if_clause else_clause |
STATEMENT_TERMINATOR job_list
block_statement = block_header STATEMENT_TERMINATOR job_list <END> arguments_or_redirections_list
block_header = if_header | for_header | while_header | function_header | begin_header
if_header = IF job
block_header = for_header | while_header | function_header | begin_header
for_header = FOR var_name IN arguments_or_redirections_list
while_header = WHILE statement
begin_header = BEGIN
function_header = FUNCTION function_name arguments_or_redirections_list
#(TODO: functions should not support taking redirections in their arguments)
# A boolean statement is AND or OR or NOT