Skip to content

Commit

Permalink
fix: Semantic analysis fails with assignment to identifier in braces (#…
Browse files Browse the repository at this point in the history
…56)

* test: add fix and test for failing test case

* fix: added stronger test case

* fix: added stronger test case
  • Loading branch information
Sh0g0-1758 authored Feb 17, 2025
1 parent 52d1e33 commit 927db87
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 6 deletions.
2 changes: 1 addition & 1 deletion expected_results.json

Large diffs are not rendered by default.

65 changes: 60 additions & 5 deletions parser/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,36 @@ void parser::parse_statement(std::vector<token::Token> &tokens,
}
}

std::pair<bool, int>
parser::is_single_identifier_parentheses(std::vector<token::Token> &tokens) {
int i = 0;
int NUM_TOKENS = tokens.size();
while (i < NUM_TOKENS) {
if (tokens[i].get_token() == token::TOKEN::OPEN_PARANTHESES) {
i++;
} else {
break;
}
}
if (tokens[i].get_token() == token::TOKEN::IDENTIFIER) {
int num_open_parentheses = i;
int tmp = i;
i++;
while (i < NUM_TOKENS) {
if (tokens[i].get_token() == token::TOKEN::CLOSE_PARANTHESES) {
tmp--;
i++;
} else {
break;
}
}
if (tmp == 0) {
return {true, num_open_parentheses};
}
}
return {false, 0};
}

void parser::parse_factor(std::vector<token::Token> &tokens,
std::shared_ptr<ast::AST_factor_Node> factor) {
if (tokens[0].get_token() == token::TOKEN::CONSTANT) {
Expand All @@ -265,11 +295,36 @@ void parser::parse_factor(std::vector<token::Token> &tokens,
parse_unary_op(tokens, factor);
parse_factor(tokens, factor);
} else if (tokens[0].get_token() == token::TOKEN::OPEN_PARANTHESES) {
tokens.erase(tokens.begin());
MAKE_SHARED(ast::AST_exp_Node, exp);
parse_exp(tokens, exp);
factor->set_exp_node(std::move(exp));
EXPECT(token::TOKEN::CLOSE_PARANTHESES);
/**
* Simplification for Single-Identifier Parentheses
*
* When encountering an expression with a single identifier wrapped in
* parentheses, e.g., (identifier), we treat it as a simple identifier
* rather than a complex expression. This optimization significantly reduces
* complexity during semantic analysis by avoiding unnecessary nested
* expression handling.
*
* Example:
* Input: (((((((((((((((((a)))))))))))))))))
* Treats as: a
*/
std::pair<bool, int> res = is_single_identifier_parentheses(tokens);
if (res.first) {
for (int i = 0; i < res.second; i++) {
tokens.erase(tokens.begin());
}
EXPECT_IDENTIFIER();
factor->set_identifier_node(std::move(identifier));
for (int i = 0; i < res.second; i++) {
tokens.erase(tokens.begin());
}
} else {
tokens.erase(tokens.begin());
MAKE_SHARED(ast::AST_exp_Node, exp);
parse_exp(tokens, exp);
factor->set_exp_node(std::move(exp));
EXPECT(token::TOKEN::CLOSE_PARANTHESES);
}
} else {
success = false;
error_messages.emplace_back("Expected constant, unary operator, semicolon "
Expand Down
2 changes: 2 additions & 0 deletions parser/parser.hh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ private:
void parse_binop(std::vector<token::Token> &tokens,
std::shared_ptr<ast::AST_binop_Node> binop);
void expect(token::TOKEN actual_token, token::TOKEN expected_token);
std::pair<bool, int>
is_single_identifier_parentheses(std::vector<token::Token> &tokens);
void eof_error(token::Token token);
void pretty_print_exp(std::shared_ptr<ast::AST_exp_Node> exp);
void pretty_print_factor(std::shared_ptr<ast::AST_factor_Node> factor);
Expand Down
4 changes: 4 additions & 0 deletions tests/chapter_5/valid/paranthesis_assignment.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
int main(void) {
int a = 69;
return (((((((((((((((((((((((((a))))))))))))))))))))))))) = 42;
}

0 comments on commit 927db87

Please sign in to comment.