Skip to content

Commit d948bdd

Browse files
authored
fixed bug of symbol table showing error for duplicate symbols (#48)
1 parent d9fdeef commit d948bdd

File tree

7 files changed

+234
-8
lines changed

7 files changed

+234
-8
lines changed

src/include/lexer/lexer.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,25 @@ class Lexer {
129129
*/
130130
symbol_table::SymbolTable symbol_table_;
131131

132+
/**
133+
* checks if a variable is directly present
134+
* after a declared datatype
135+
*
136+
* Use case 1
137+
* int a = 5; for token 'a' direct_before_datatype = true
138+
* else false
139+
*
140+
* Use case 2
141+
*
142+
* int z = 5 + y , t = 5 , r = 5 + s;
143+
* for token z, direct_before_datatype = true
144+
* for token y, direct_before_datatype = false
145+
* for token t, direct_before_datatype = true
146+
* for token r, direct_before_datatype = true
147+
* for token s, direct_before_datatype = false
148+
*/
149+
bool direct_before_datatype_{false};
150+
132151
public:
133152
Lexer() = default;
134153

@@ -162,6 +181,11 @@ class Lexer {
162181
* Getter for duplicate symbol errors.
163182
*/
164183
std::vector<std::string> GetDuplicateSymbolErrors();
184+
185+
/**
186+
* Getter for direct_before_datatype flag
187+
*/
188+
[[nodiscard]] const bool &GetDirectBeforeDatatypeFlag() const { return direct_before_datatype_; }
165189
}; // class Lexer
166190

167191
} // namespace lexer

src/include/symbol_table/symbol_table.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,11 @@ class SymbolTable {
113113
* Checks if the current identifier is present in the same nesting level
114114
* int the hash_table. If present reports a duplicate symbol error, that is,
115115
* inserts into the duplicate_symbols vector.
116+
* @Params : Node * node , bool direct_before_datatype
117+
* Node is the struct encapsulating the information about an identifier
118+
* direct_before_datatype is an boolean flag describing whether the identifier is declared.
116119
*/
117-
void CheckAndAddEntry(Node *node_);
120+
void CheckAndAddEntry(Node *node_, bool direct_before_datatype_);
118121

119122
/**
120123
* On scope end - sc_

src/lexer/lexer.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,35 @@ int Lexer::GetToken(std::ifstream &is) {
2424
}
2525
if (identifier_string_ == "int") {
2626
current_datatype_ = identifier_string_;
27+
direct_before_datatype_ = true;
2728
ret_token = TOK_INT;
2829
} else if (identifier_string_ == "float") {
2930
current_datatype_ = identifier_string_;
31+
direct_before_datatype_ = true;
3032
ret_token = TOK_FLOAT;
3133
} else if (identifier_string_ == "void") {
3234
current_datatype_ = identifier_string_;
35+
direct_before_datatype_ = true;
3336
ret_token = TOK_VOID;
3437
} else if (identifier_string_ == "if") {
3538
current_datatype_ = "";
39+
direct_before_datatype_ = false;
3640
ret_token = TOK_IF;
3741
} else if (identifier_string_ == "else") {
3842
current_datatype_ = "";
43+
direct_before_datatype_ = false;
3944
ret_token = TOK_ELSE;
4045
} else if (identifier_string_ == "cout") {
4146
current_datatype_ = "";
47+
direct_before_datatype_ = false;
4248
ret_token = TOK_COUT;
4349
} else if (identifier_string_ == "cin") {
4450
current_datatype_ = "";
51+
direct_before_datatype_ = false;
4552
ret_token = TOK_CIN;
4653
} else if (identifier_string_ == "main") {
4754
current_datatype_ = "";
55+
direct_before_datatype_ = false;
4856
ret_token = TOK_MAIN;
4957
} else {
5058
ret_token = TOK_IDENTIFIER;
@@ -53,7 +61,7 @@ int Lexer::GetToken(std::ifstream &is) {
5361
* if identifier insert into symbol_table
5462
*/
5563
auto *node = new symbol_table::Node(identifier_string_, current_datatype_, current_nesting_level_);
56-
symbol_table_.CheckAndAddEntry(node);
64+
symbol_table_.CheckAndAddEntry(node, direct_before_datatype_);
5765
delete node;
5866
if (!symbol_table_.GetDuplicateSymbols().empty()) {
5967
duplicate_symbol_errors_ = symbol_table_.GetDuplicateSymbols();
@@ -71,6 +79,7 @@ int Lexer::GetToken(std::ifstream &is) {
7179
// RE : [0-9]+.?[0-9]*
7280
if (isdigit(last_char) != 0) {
7381
std::string num_string;
82+
direct_before_datatype_ = false;
7483
num_string += last_char;
7584
// to check if fractional
7685
int dot_count = 0;
@@ -249,6 +258,7 @@ int Lexer::GetToken(std::ifstream &is) {
249258
if (is.eof()) {
250259
last_char = ' ';
251260
}
261+
direct_before_datatype_ = ret_token == TOK_COMMA;
252262
return ret_token;
253263
}
254264

src/symbol_table/symbol_table.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ void LinkedList::DeleteStartingNode() {
2626

2727
Node *LinkedList::GetHead() { return this->head_; }
2828

29-
void SymbolTable::CheckAndAddEntry(Node *node_) {
29+
void SymbolTable::CheckAndAddEntry(Node *node_, bool direct_before_datatype_) {
3030
// if present check if in common scope
3131
if (hash_table_.count(node_->identifier_) != 0U) {
3232
// check if using a previously declared variable.
33-
if (node_->data_type_.empty()) {
33+
if (!direct_before_datatype_) {
3434
return;
3535
}
3636
// declaring a variable

test/lexer/input3.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
int main() {
2+
int x, y;
3+
cin >> y;
4+
if (x != 0) {
5+
if (y > 0) {
6+
cout << y;
7+
}
8+
}
9+
float z = 1 + 2 + 3 + 1000/ 50 * 23.2 * (x * y * 10);
10+
}

test/lexer/lexer_test.cpp

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,3 +588,183 @@ TEST(lexer, Lexer8) {
588588
ASSERT_EQ(lex.GetDuplicateSymbolErrors().size(), 0);
589589
ASSERT_EQ(lex.GetUndeclaredSymbolErrors().size(), 0);
590590
}
591+
592+
TEST(lexer, Lexer9) {
593+
std::string filename("../test/lexer/input3.txt");
594+
Lexer lex = Lexer();
595+
596+
std::ifstream is(filename);
597+
int token;
598+
bool flag = lex.GetDirectBeforeDatatypeFlag();
599+
ASSERT_EQ(flag, false);
600+
token = lex.GetToken(is);
601+
flag = lex.GetDirectBeforeDatatypeFlag();
602+
ASSERT_EQ(flag, true);
603+
ASSERT_EQ(jucc::lexer::TOK_INT, token);
604+
token = lex.GetToken(is);
605+
ASSERT_EQ(jucc::lexer::TOK_MAIN, token);
606+
token = lex.GetToken(is);
607+
ASSERT_EQ(jucc::lexer::TOK_PAREN_OPEN, token);
608+
token = lex.GetToken(is);
609+
flag = lex.GetDirectBeforeDatatypeFlag();
610+
ASSERT_EQ(flag, false);
611+
ASSERT_EQ(jucc::lexer::TOK_PAREN_CLOSE, token);
612+
token = lex.GetToken(is);
613+
ASSERT_EQ(jucc::lexer::TOK_CURLY_OPEN, token);
614+
token = lex.GetToken(is);
615+
flag = lex.GetDirectBeforeDatatypeFlag();
616+
ASSERT_EQ(flag, true);
617+
ASSERT_EQ(jucc::lexer::TOK_INT, token);
618+
token = lex.GetToken(is);
619+
flag = lex.GetDirectBeforeDatatypeFlag();
620+
ASSERT_EQ(flag, true);
621+
ASSERT_EQ(jucc::lexer::TOK_IDENTIFIER, token);
622+
token = lex.GetToken(is);
623+
flag = lex.GetDirectBeforeDatatypeFlag();
624+
ASSERT_EQ(flag, true);
625+
ASSERT_EQ(jucc::lexer::TOK_COMMA, token);
626+
token = lex.GetToken(is);
627+
flag = lex.GetDirectBeforeDatatypeFlag();
628+
ASSERT_EQ(flag, true);
629+
ASSERT_EQ(jucc::lexer::TOK_IDENTIFIER, token);
630+
token = lex.GetToken(is);
631+
flag = lex.GetDirectBeforeDatatypeFlag();
632+
ASSERT_EQ(flag, false);
633+
ASSERT_EQ(jucc::lexer::TOK_SEMICOLON, token);
634+
token = lex.GetToken(is);
635+
flag = lex.GetDirectBeforeDatatypeFlag();
636+
ASSERT_EQ(flag, false);
637+
ASSERT_EQ(jucc::lexer::TOK_CIN, token);
638+
token = lex.GetToken(is);
639+
flag = lex.GetDirectBeforeDatatypeFlag();
640+
ASSERT_EQ(flag, false);
641+
ASSERT_EQ(jucc::lexer::TOK_RIGHT_SHIFT, token);
642+
token = lex.GetToken(is);
643+
flag = lex.GetDirectBeforeDatatypeFlag();
644+
ASSERT_EQ(flag, false);
645+
ASSERT_EQ(jucc::lexer::TOK_IDENTIFIER, token);
646+
token = lex.GetToken(is);
647+
ASSERT_EQ(jucc::lexer::TOK_SEMICOLON, token);
648+
token = lex.GetToken(is);
649+
ASSERT_EQ(jucc::lexer::TOK_IF, token);
650+
token = lex.GetToken(is);
651+
ASSERT_EQ(jucc::lexer::TOK_PAREN_OPEN, token);
652+
token = lex.GetToken(is);
653+
flag = lex.GetDirectBeforeDatatypeFlag();
654+
ASSERT_EQ(flag, false);
655+
ASSERT_EQ(jucc::lexer::TOK_IDENTIFIER, token);
656+
token = lex.GetToken(is);
657+
ASSERT_EQ(jucc::lexer::TOK_NOT_EQUAL_TO, token);
658+
token = lex.GetToken(is);
659+
flag = lex.GetDirectBeforeDatatypeFlag();
660+
ASSERT_EQ(flag, false);
661+
ASSERT_EQ(jucc::lexer::TOK_DECIMAL, token);
662+
token = lex.GetToken(is);
663+
ASSERT_EQ(jucc::lexer::TOK_PAREN_CLOSE, token);
664+
token = lex.GetToken(is);
665+
ASSERT_EQ(jucc::lexer::TOK_CURLY_OPEN, token);
666+
token = lex.GetToken(is);
667+
ASSERT_EQ(jucc::lexer::TOK_IF, token);
668+
token = lex.GetToken(is);
669+
ASSERT_EQ(jucc::lexer::TOK_PAREN_OPEN, token);
670+
token = lex.GetToken(is);
671+
flag = lex.GetDirectBeforeDatatypeFlag();
672+
ASSERT_EQ(flag, false);
673+
ASSERT_EQ(jucc::lexer::TOK_IDENTIFIER, token);
674+
token = lex.GetToken(is);
675+
flag = lex.GetDirectBeforeDatatypeFlag();
676+
ASSERT_EQ(flag, false);
677+
ASSERT_EQ(jucc::lexer::TOK_GREATER_THAN, token);
678+
token = lex.GetToken(is);
679+
ASSERT_EQ(jucc::lexer::TOK_DECIMAL, token);
680+
token = lex.GetToken(is);
681+
ASSERT_EQ(jucc::lexer::TOK_PAREN_CLOSE, token);
682+
token = lex.GetToken(is);
683+
ASSERT_EQ(jucc::lexer::TOK_CURLY_OPEN, token);
684+
token = lex.GetToken(is);
685+
ASSERT_EQ(jucc::lexer::TOK_COUT, token);
686+
token = lex.GetToken(is);
687+
ASSERT_EQ(jucc::lexer::TOK_LEFT_SHIFT, token);
688+
token = lex.GetToken(is);
689+
ASSERT_EQ(jucc::lexer::TOK_IDENTIFIER, token);
690+
token = lex.GetToken(is);
691+
ASSERT_EQ(jucc::lexer::TOK_SEMICOLON, token);
692+
token = lex.GetToken(is);
693+
ASSERT_EQ(jucc::lexer::TOK_CURLY_CLOSE, token);
694+
token = lex.GetToken(is);
695+
ASSERT_EQ(jucc::lexer::TOK_CURLY_CLOSE, token);
696+
token = lex.GetToken(is);
697+
flag = lex.GetDirectBeforeDatatypeFlag();
698+
ASSERT_EQ(flag, true);
699+
ASSERT_EQ(jucc::lexer::TOK_FLOAT, token);
700+
token = lex.GetToken(is);
701+
flag = lex.GetDirectBeforeDatatypeFlag();
702+
ASSERT_EQ(flag, true);
703+
ASSERT_EQ(jucc::lexer::TOK_IDENTIFIER, token);
704+
token = lex.GetToken(is);
705+
flag = lex.GetDirectBeforeDatatypeFlag();
706+
ASSERT_EQ(flag, false);
707+
ASSERT_EQ(jucc::lexer::TOK_ASSIGNMENT, token);
708+
token = lex.GetToken(is);
709+
flag = lex.GetDirectBeforeDatatypeFlag();
710+
ASSERT_EQ(flag, false);
711+
ASSERT_EQ(jucc::lexer::TOK_DECIMAL, token);
712+
token = lex.GetToken(is);
713+
flag = lex.GetDirectBeforeDatatypeFlag();
714+
ASSERT_EQ(flag, false);
715+
ASSERT_EQ(jucc::lexer::TOK_PLUS, token);
716+
token = lex.GetToken(is);
717+
flag = lex.GetDirectBeforeDatatypeFlag();
718+
ASSERT_EQ(flag, false);
719+
ASSERT_EQ(jucc::lexer::TOK_DECIMAL, token);
720+
token = lex.GetToken(is);
721+
flag = lex.GetDirectBeforeDatatypeFlag();
722+
ASSERT_EQ(flag, false);
723+
ASSERT_EQ(jucc::lexer::TOK_PLUS, token);
724+
token = lex.GetToken(is);
725+
flag = lex.GetDirectBeforeDatatypeFlag();
726+
ASSERT_EQ(flag, false);
727+
ASSERT_EQ(jucc::lexer::TOK_DECIMAL, token);
728+
token = lex.GetToken(is);
729+
flag = lex.GetDirectBeforeDatatypeFlag();
730+
ASSERT_EQ(flag, false);
731+
ASSERT_EQ(jucc::lexer::TOK_PLUS, token);
732+
token = lex.GetToken(is);
733+
flag = lex.GetDirectBeforeDatatypeFlag();
734+
ASSERT_EQ(flag, false);
735+
ASSERT_EQ(jucc::lexer::TOK_DECIMAL, token);
736+
token = lex.GetToken(is);
737+
ASSERT_EQ(jucc::lexer::TOK_DIVIDE, token);
738+
token = lex.GetToken(is);
739+
ASSERT_EQ(jucc::lexer::TOK_DECIMAL, token);
740+
token = lex.GetToken(is);
741+
ASSERT_EQ(jucc::lexer::TOK_MULTIPLY, token);
742+
token = lex.GetToken(is);
743+
ASSERT_EQ(jucc::lexer::TOK_FRACTIONAL, token);
744+
token = lex.GetToken(is);
745+
ASSERT_EQ(jucc::lexer::TOK_MULTIPLY, token);
746+
token = lex.GetToken(is);
747+
ASSERT_EQ(jucc::lexer::TOK_PAREN_OPEN, token);
748+
token = lex.GetToken(is);
749+
flag = lex.GetDirectBeforeDatatypeFlag();
750+
ASSERT_EQ(flag, false);
751+
ASSERT_EQ(jucc::lexer::TOK_IDENTIFIER, token);
752+
token = lex.GetToken(is);
753+
ASSERT_EQ(jucc::lexer::TOK_MULTIPLY, token);
754+
token = lex.GetToken(is);
755+
flag = lex.GetDirectBeforeDatatypeFlag();
756+
ASSERT_EQ(flag, false);
757+
ASSERT_EQ(jucc::lexer::TOK_IDENTIFIER, token);
758+
token = lex.GetToken(is);
759+
ASSERT_EQ(jucc::lexer::TOK_MULTIPLY, token);
760+
token = lex.GetToken(is);
761+
ASSERT_EQ(jucc::lexer::TOK_DECIMAL, token);
762+
token = lex.GetToken(is);
763+
ASSERT_EQ(jucc::lexer::TOK_PAREN_CLOSE, token);
764+
token = lex.GetToken(is);
765+
ASSERT_EQ(jucc::lexer::TOK_SEMICOLON, token);
766+
token = lex.GetToken(is);
767+
ASSERT_EQ(jucc::lexer::TOK_CURLY_CLOSE, token);
768+
token = lex.GetToken(is);
769+
ASSERT_EQ(jucc::lexer::TOK_EOF, token);
770+
}

test/symbol_table/symbol_table_test.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,22 @@ TEST(symbolTable, SymbolTable4) {
4646
* Check Deletion
4747
*/
4848
SymbolTable smb = SymbolTable();
49-
5049
Node *node = new Node("x", "int", 0);
51-
smb.CheckAndAddEntry(node);
50+
smb.CheckAndAddEntry(node, true);
5251
delete node;
5352
Node *head = smb.GetLinkedListById("x");
5453
ASSERT_EQ(std::string("int"), head->data_type_);
5554
ASSERT_EQ(0, head->nesting_level_);
5655

5756
Node *node1 = new Node("x", "int", 1);
58-
smb.CheckAndAddEntry(node1);
57+
smb.CheckAndAddEntry(node1, true);
5958
delete node1;
6059
head = smb.GetLinkedListById("x");
6160
ASSERT_EQ(std::string("int"), head->data_type_);
6261
ASSERT_EQ(1, head->nesting_level_);
6362

6463
Node *node2 = new Node("x", "int", 1);
65-
smb.CheckAndAddEntry(node2);
64+
smb.CheckAndAddEntry(node2, true);
6665
delete node2;
6766

6867
std::vector<std::string> dups = smb.GetDuplicateSymbols();

0 commit comments

Comments
 (0)