Skip to content

Commit

Permalink
fix: parser backend
Browse files Browse the repository at this point in the history
  • Loading branch information
zeim839 committed May 10, 2023
1 parent aaa8250 commit 84a2205
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 57 deletions.
23 changes: 18 additions & 5 deletions src/frontend/backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,15 @@ class Scope

// Test whether an identifier string has been defined.
bool is_defined(const std::string& ident)
{ return (this->lookup(ident) != NULL); }
{
if (this->lookup(ident))
return true;

if (this->parent())
return this->parent()->is_defined(ident);

return false;
}

/*
* Defines a new named_object in the scope.
Expand Down Expand Up @@ -207,6 +215,12 @@ class Backend
return this->_current_scope;
}

Scope* enter_scope(Scope* scope)
{
this->_current_scope = scope;
return this->_current_scope;
}

/*
* Exits out of the current scope and into the parent scope.
* Always returns the most current scope.
Expand Down Expand Up @@ -292,14 +306,13 @@ class Backend
virtual Bstatement* if_statement(Bexpression*, Scope*, Location) = 0;

/*
* Returns a for-loop statement. The ind statement can be any type
* of statement. Cond must be a conditional statement, inc must
* be an increment/decrement statement. The statements may be NULL.
* Returns a for-loop statement. Cond must be a conditional statement,
* inc must be an increment/decrement statement. The statements may be NULL.
* The scope keeps track of statements within the for-loop, they
* must be parsed by this function.
*/
virtual Bstatement* for_statement
(Bstatement* ind, Bstatement* cond, Bstatement* inc, Scope*, Location) = 0;
(Bstatement* cond, Bstatement* inc, Scope*, Location) = 0;

/*
* Returns an expression wrapped as a statement. The expression must
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/expressions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Bexpression* Binary_expression::do_get_backend(Backend* backend)

// Create backend expressions
Bexpression* left = this->left()->get_backend(backend);
Bexpression* right = this->left()->get_backend(backend);
Bexpression* right = this->right()->get_backend(backend);
RIN_ASSERT(left != NULL && right != NULL);

return backend->binary_expression(this->op(), left,
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/operators.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/
int OPERATOR_PRECEDENCE[] =
{
-2, 4, 4, 5, 5, 5, 1, 0, 0, 0, 2, 3, 3,
-2, 4, 4, 5, 5, 5, 1, 0, 6, 6, 2, 3, 3,
-2, 6, 2, 3, 3, -1, -2, -2, -1, -2, -2, -2
};

Expand Down
102 changes: 72 additions & 30 deletions src/frontend/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* line as condition. Perhaps this should be changed?
*
* TODO: minus (-) as a unary operator.
* TODO: pass any statement type into for loops.
* TODO: for-loop increment statement parses expressions.
*/

Expand Down Expand Up @@ -44,7 +43,7 @@ void Parser::parse(bool is_supercontext)
}

/*
* Prevents errors being issued when a non-super scope has not
* Prevents errors being issued when a non-super scope has no
* statements, i.e for-loop with no statements.
*/
if (this->_scanner->peek_token().classification() == Token::TOKEN_EOL) {
Expand All @@ -54,10 +53,9 @@ void Parser::parse(bool is_supercontext)

Statement* next = this->parse_next();
RIN_ASSERT(next != NULL);
if (!next->is_invalid()) {
if (!next->is_invalid())
this->_backend->push_statement(next->get_backend(this->_backend));
delete next;
}
delete next;
}

// Issue Scanner errors, if any.
Expand Down Expand Up @@ -114,10 +112,6 @@ Statement* Parser::parse_next()
return this->parse_assignment_statement();
}

rin_error_at(tk.location(),
"Expected statement but got hanging token of type %s",
&tk.classification_as_string()[0]);

is_invalid_statement:
this->_scanner->next_token();
this->_scanner->skip_line();
Expand All @@ -143,7 +137,6 @@ Statement* Parser::parse_if_statement()
"If-statement expected left-brace '{' but received %s instead",
expect_lbrace.str());
this->_scanner->skip_line();
delete condition;
return Statement::make_invalid(if_rid.location());
}

Expand Down Expand Up @@ -260,9 +253,15 @@ Statement* Parser::parse_for_statement()
return Statement::make_invalid(lbrace.location());
}

// Parse for-loop scope
// Add induction statement to for-loop scope.
Scope* loop_scope = this->_backend->enter_scope();
if (ind_stmt) loop_scope->push_statement(ind_stmt->get_backend(this->_backend));

this->_backend->enter_scope();

// Parse statements in for-loop scope.
this->parse(false);
this->_backend->leave_scope();

// Create for-loop statement
For_statement* loop_stmt = new For_statement(ind_stmt, cond_stmt,
Expand Down Expand Up @@ -299,7 +298,7 @@ Statement* Parser::parse_var_dec_statement()

// Create var declaration
Named_object* obj = new Named_object(*ident.identifier(), ident.location());
return Statement::make_variable_declaration(obj);
return Statement::make_variable_declaration(obj);
}

// Create a declaration and then parse it's assignment
Expand Down Expand Up @@ -381,10 +380,9 @@ class Expression_node
// The node type
enum node_type { INVALID_NODE, OPERATOR_NODE, VAR_NODE, FLOAT_NODE };

Expression_node(Token token, Token peek)
Expression_node(Token token)
{
this->_location = token.location();
this->_next_str = peek.string();
this->_str = token.string();

Token::Classification cls = token.classification();
Expand Down Expand Up @@ -419,6 +417,27 @@ class Expression_node
}
}

// Return the rightmost child or itself.
Expression_node* rightmost_child()
{
if (this->is_invalid())
return NULL;

if (this->type() == VAR_NODE || this->type() == FLOAT_NODE)
return this;

if (this->is_unary() && this->left_child != NULL)
return this->left_child->rightmost_child();

if (this->left_child != NULL && this->right_child == NULL)
return this->left_child->rightmost_child();

if (this->right_child != NULL)
return this->right_child->rightmost_child();

return NULL;
}

/*
* If the node falls out of scope then we don't want
* to delete the underlying expression.
Expand Down Expand Up @@ -501,10 +520,6 @@ class Expression_node
return true;
}

// Returns the C-string pointer of the next token for debug.
char* next_str()
{ return &this->_next_str[0]; }

// Returns the C-string pointer of the expression for debug.
char* str()
{ return &this->_str[0]; }
Expand Down Expand Up @@ -544,9 +559,6 @@ class Expression_node

Location _location;

// Next token string, for debugging.
std::string _next_str;

// Own str
std::string _str;

Expand Down Expand Up @@ -602,7 +614,7 @@ void __abort_expr_parse
}

// Recursively parses a child of an expression node
Expression_node* __parse_ast_node(std::deque<Expression_node*>& output)
Expression_node* __parse_ast_node(std::deque<Expression_node*>& output, bool& printed)
{
if (output.empty()) return NULL;
Expression_node* child = output.back();
Expand All @@ -619,7 +631,7 @@ Expression_node* __parse_ast_node(std::deque<Expression_node*>& output)
return child;

// --- Child is an operator ---
Expression_node* right = __parse_ast_node(output);
Expression_node* right = __parse_ast_node(output, printed);
if (!right) {
child->abort();
delete child;
Expand All @@ -631,9 +643,19 @@ Expression_node* __parse_ast_node(std::deque<Expression_node*>& output)
return child;
}

Expression_node* left = __parse_ast_node(output);
/*
* If left most operator is missing, then that means
* a binary operator was used incorrectly.
*/
Expression_node* left = __parse_ast_node(output, printed);
if (!left) {
child->abort();
if (!printed) {
rin_error_at(child->location(),
"Invalid type argument of %s",
child->str());
printed = true;
}
delete child;
return NULL;
}
Expand Down Expand Up @@ -676,7 +698,7 @@ Expression* Parser::parse_expression(RIN_OPERATOR terminal)

case Token::TOKEN_FLOAT:
case Token::TOKEN_IDENT:
node = new Expression_node(token, this->_scanner->peek_token());
node = new Expression_node(token);
break;

case Token::TOKEN_EOL:
Expand All @@ -696,9 +718,17 @@ Expression* Parser::parse_expression(RIN_OPERATOR terminal)
goto next_token;

case Token::TOKEN_EOF:
// EOF can count as a semicolon too

/*
* EOF can count as a semicolon as long as it is not
* preceded by another operator (with parenthesis
* being the only exception).
*/
if (terminal == OPER_SEMICOLON &&
prev_token.classification() != Token::TOKEN_OPERATOR) {
(prev_token.classification() != Token::TOKEN_OPERATOR
|| OPERATOR_PRECEDENCE[prev_token.op()] == -1
|| prev_token.op() == OPER_INC
|| prev_token.op() == OPER_DEC)) {
resolves = true;
goto exit_loop;
}
Expand Down Expand Up @@ -776,6 +806,9 @@ Expression* Parser::parse_expression(RIN_OPERATOR terminal)
if (operators.empty() || !operators.top()->is_open_paren()) {
rin_error_at(token.location(), "Unmatched close parenthesis");
__abort_expr_parse(operators, output);

// Consume the parenthesis to prevent re-emitting errors.
prev_token = this->_scanner->next_token();
return NULL;
}

Expand Down Expand Up @@ -825,13 +858,23 @@ Expression* Parser::parse_expression(RIN_OPERATOR terminal)
}

// --- Create Abstract Syntax Tree ---
Expression_node* super_root = __parse_ast_node(output);
bool __found_err = false;
Expression_node* super_root = __parse_ast_node(output, __found_err);
if (!super_root) {
rin_error_at(start_loc, "Malformed expression");
__abort_expr_parse(operators, output);
return NULL;
}

// Missing operator
if (!output.empty()) {
Expression_node* rightmost = super_root->rightmost_child();
rin_error_at(super_root->location(), "Expected ';' before '%s'",
rightmost->str());
__abort_expr_parse(operators, output);
delete super_root;
return NULL;
}

// --- Done Parsing ---
Expression* binary = super_root->get_expression();

Expand All @@ -842,4 +885,3 @@ Expression* Parser::parse_expression(RIN_OPERATOR terminal)
delete super_root;
return binary;
}

2 changes: 1 addition & 1 deletion src/frontend/scanner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ void Scanner::acknowledge(Token tok)
return;
}
if (is_righthand_op(tok.op())) {
rin_error_at(tok.location(), "Unexpected paired operator %s",
rin_error_at(tok.location(), "Unexpected %s",
&operator_name(tok.op())[0]);
}
}
Expand Down
27 changes: 9 additions & 18 deletions src/frontend/statements.cc
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,7 @@ Bstatement* Variable_declaration_statement::do_get_backend(Backend* backend)
// If_statement implementation

If_statement::~If_statement()
{
delete this->_cond;
delete this->_then_block;
}
{ delete this->_cond; }

Bstatement* If_statement::do_get_backend(Backend* backend)
{
Expand Down Expand Up @@ -134,24 +131,14 @@ For_statement::~For_statement()
delete this->_ind_var;
delete this->_cond;
delete this->_inc;
delete this->_statements;
}

Bstatement* For_statement::do_get_backend(Backend* backend)
{
RIN_ASSERT(backend);
RIN_ASSERT(this->has_statements());

/*
* Induction statement may be NULL.
* If not NULL, then it can be any statement (except INVALID).
*/
Statement* ind_stmt = this->ind_var();
Bstatement* ind_bstmt = NULL;
if (ind_stmt != NULL) {
RIN_ASSERT(ind_stmt->classification() != STATEMENT_INVALID);
ind_bstmt = ind_stmt->get_backend(backend);
}
backend->enter_scope(this->statements());

/*
* Condition statement may be NULL.
Expand Down Expand Up @@ -186,8 +173,10 @@ Bstatement* For_statement::do_get_backend(Backend* backend)
inc_bstmt = inc_stmt->get_backend(backend);
}

backend->leave_scope();

// Build backend for-loop statement.
return backend->for_statement(ind_bstmt, cond_bstmt, inc_bstmt,
return backend->for_statement(cond_bstmt, inc_bstmt,
this->statements(), this->location());
}

Expand Down Expand Up @@ -246,8 +235,10 @@ Bstatement* Compound_statement::do_get_backend(Backend* backend)
RIN_ASSERT(this->second());

// Statements are not invalid.
RIN_ASSERT(this->first()->classification() != STATEMENT_INVALID);
RIN_ASSERT(this->second()->classification() != STATEMENT_INVALID);
if (this->first()->classification() == STATEMENT_INVALID ||
this->second()->classification() == STATEMENT_INVALID) {
return backend->invalid_statement();
}

// Build statements.
Bstatement* first = this->first()->get_backend(backend);
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/statements.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ class Assignment_statement : public Statement

// Return right hand side of assignment
Expression* rhs() const
{ return this->_lhs; }
{ return this->_rhs; }

protected:
Bstatement* do_get_backend(Backend* backend);
Expand Down

0 comments on commit 84a2205

Please sign in to comment.