Skip to content

Commit

Permalink
Merge branch 'CodieTamida:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
NLTN authored Mar 30, 2024
2 parents 6ec9340 + a326c7d commit 16e254d
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 26 deletions.
97 changes: 71 additions & 26 deletions components/syntax_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ def __r12_declaration(self):
Applies the grammar rule 12:
<Declaration> ::= <Qualifier > <IDs>
"""
self.debug_print("<Declaration> ::= <Qualifier > <IDs>")
self.debug_print_current_token()
self.__r8_qualifier()
self.__r13_ids()
Expand Down Expand Up @@ -437,9 +438,8 @@ def __r17_assign(self):
"""
self.debug_print("<Assign> -> <Identifier> = <Expression> ;")

self.debug_print_current_token()

if self.__current_token.lexeme == "=":
self.debug_print_current_token()
self.__match(self.__current_token.lexeme) # Move to the next token
self.__r25a_expression()

Expand All @@ -463,17 +463,12 @@ def __r19_return(self):
R` = <Return Prime>
"""

if self.__current_token.lexeme == "return":
self.debug_print_current_token()
expression = f'<Return> -> return <Return Prime>'
self.debug_print(expression)

self.__match(self.__current_token.lexeme)

self.__r19_return_b_prime()
else:
self.debug_print(f"Expecting return keyword, but read {self.__current_token.lexeme}")


self.debug_print_current_token()
self.__match("return")
self.debug_print(f"<Return> -> return <Return Prime>")
self.__r19_return_b_prime()

def __r19_return_b_prime(self):
"""
R' --> ; | E
Expand All @@ -490,15 +485,15 @@ def __r19_return_b_prime(self):


# Check to see if <Expression>, after left-recursion, leads E -> TE'

else:
self.debug_print(f"<Return Prime> -> <Expression>;")
self.__r25a_expression()
self.__match(';')


def __r20_print(self):
self.debug_print(f"<Print> -> print ( <Expression> );")
self.__match("print")
self.debug_print_current_token()
self.__match('(')
self.__r25a_expression()
self.debug_print_current_token()
Expand All @@ -510,13 +505,66 @@ def __r21_scan(self):
raise NotImplementedError("Must implement this method!")

def __r22_while(self):
raise NotImplementedError("Must implement this method!")
"""
Applies the grammar rule 24:
<While> -> while ( <Condition> ) <Statement> endwhile
Raises:
SyntaxError:
"""
self.debug_print_current_token()
self.debug_print("<While> -> while ( <Condition> ) <Statement> endwhile")

# Match the beginning of <While>, indicated by "while".
self.__match("while")

# Match the open parenthesis, indicated by "(".
self.debug_print_current_token()
self.__match("(")

# Apply rule 23 <Condition>
self.__r23_condition()

# Match the close parenthesis, indicated by ")".
self.debug_print_current_token()
self.__match(")")

# Apply rule 15 <Statement>
self.__r15_statement()

# Match the end of <While>, indicated by "endwhile".
self.debug_print_current_token()
self.__match("endwhile")

def __r23_condition(self):
raise NotImplementedError("Must implement this method!")
"""
Applies the grammar rule 23:
<Condition> -> <Expression> <Relop> <Expression>
"""
self.debug_print("<Condition> -> <Expression> <Relop> <Expression>")
self.__r25a_expression()
self.__r24_relop()
self.__r25a_expression()

def __r24_relop(self):
raise NotImplementedError("Must implement this method!")
"""
Applies the grammar rule 24:
<Relop> -> == | != | > | < | <= | =>
Raises:
SyntaxError: If the current token is not a valid relational operator.
"""
relation_operators = {"==", "!=", ">", "<", "<=", "=>"}
lexeme = self.__current_token.lexeme.lower()

if lexeme in relation_operators:
self.debug_print_current_token()
self.debug_print(f"<Relop> -> {self.__current_token.lexeme}")
self.__match(self.__current_token.lexeme)
else:
text1 = f"Relation operator is missing."
text2 = f"Expected `{relation_operators}`, but found {self.__current_token.lexeme}"
raise SyntaxError(f"{text1}\n{text2}")

def __r25a_expression(self):
"""
Expand Down Expand Up @@ -546,10 +594,11 @@ def __r25b_expression_prime(self):
"""
# Check for '+' or '-' case
if self.__current_token.lexeme == "+" or self.__current_token.lexeme == "-":
self.debug_print_current_token()
self.debug_print(
f"<Expression Prime> -> {self.__current_token.lexeme} <Term> <Expression Prime>")
self.__match(self.__current_token.lexeme) # Move to the next token
self.debug_print_current_token()

self.__r26a_term()
self.__r25b_expression_prime()
# Handle Epsilon case
Expand All @@ -566,6 +615,7 @@ def __r26a_term(self):
T is <Term>
T' is <Term Prime>
"""
# self.debug_print_current_token()
self.debug_print("<Term> -> <Factor> <Term Prime>")

self.__r27_factor()
Expand All @@ -582,17 +632,15 @@ def __r26b_term_prime(self):
T' is <Term Prime>
"""

# Print current token for debugging purposes
self.debug_print_current_token()

# Check for '*' or '/' case
if self.__current_token.lexeme == "*" or self.__current_token.lexeme == "/":
self.debug_print_current_token()

# Generate and print production rule text
text = f"<Term Prime> -> {self.__current_token.lexeme} <Factor> <Term Prime>"
self.debug_print(text)

self.__match(self.__current_token.lexeme) # Move to the next token
self.debug_print_current_token()

# Apply production rules for Factor and Term Prime recursively
self.__r27_factor()
Expand Down Expand Up @@ -678,8 +726,5 @@ def __r28b_primary_prime(self):
self.debug_print_current_token()
self.__match(")") # Match and Move to the next token
text = "( <IDs> )"
# Handle Epsilon case
else:
self.debug_print("<Primary Prime> -> ε")

return text
114 changes: 114 additions & 0 deletions tests/test_SA_r22_while.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import unittest
import os
from tests.helpers import write_to_file, get_result_from_parser


class WhileTestCase(unittest.TestCase):
SAMPLE_FILE_PATH = "tests/sample1.txt"

def setUp(self):
if os.path.exists(self.SAMPLE_FILE_PATH):
os.remove(self.SAMPLE_FILE_PATH)

def tearDown(self):
if os.path.exists(self.SAMPLE_FILE_PATH):
os.remove(self.SAMPLE_FILE_PATH)

def test_while(self):
# Arrange
input_string = "$ $ $ while (a == true) b = 1; endwhile $"
expected_output = True

# Act
write_to_file(self.SAMPLE_FILE_PATH, input_string)
actual_output = get_result_from_parser(self.SAMPLE_FILE_PATH)

# Assert
self.assertEqual(actual_output, expected_output)

def test_0_conditions(self):
# Arrange
input_string = "$ $ $ while () b = 1; endwhile $"
expected_output = False

# Act
write_to_file(self.SAMPLE_FILE_PATH, input_string)
actual_output = get_result_from_parser(self.SAMPLE_FILE_PATH)

# Assert
self.assertEqual(actual_output, expected_output)

def test_no_relop(self):
# Arrange
input_string = "$ $ $ while (a) b = 1; endwhile $"
expected_output = False

# Act
write_to_file(self.SAMPLE_FILE_PATH, input_string)
actual_output = get_result_from_parser(self.SAMPLE_FILE_PATH)

# Assert
self.assertEqual(actual_output, expected_output)

def test_2_conditions(self):
# Arrange
input_string = "$ $ $ while (a == true, b == false) b = 1; endwhile $"
expected_output = False

# Act
write_to_file(self.SAMPLE_FILE_PATH, input_string)
actual_output = get_result_from_parser(self.SAMPLE_FILE_PATH)

# Assert
self.assertEqual(actual_output, expected_output)

def test_no_open_parenthesis(self):
# Arrange
input_string = "$ $ $ while a == true) b = 1; endwhile $"
expected_output = False

# Act
write_to_file(self.SAMPLE_FILE_PATH, input_string)
actual_output = get_result_from_parser(self.SAMPLE_FILE_PATH)

# Assert
self.assertEqual(actual_output, expected_output)

def test_no_close_parenthesis(self):
# Arrange
input_string = "$ $ $ while (a == true b = 1; endwhile $"
expected_output = False

# Act
write_to_file(self.SAMPLE_FILE_PATH, input_string)
actual_output = get_result_from_parser(self.SAMPLE_FILE_PATH)

# Assert
self.assertEqual(actual_output, expected_output)

def test_no_statement(self):
# Arrange
input_string = "$ $ $ while (a == true) endwhile $"
expected_output = False

# Act
write_to_file(self.SAMPLE_FILE_PATH, input_string)
actual_output = get_result_from_parser(self.SAMPLE_FILE_PATH)

# Assert
self.assertEqual(actual_output, expected_output)

def test_no_endwhile(self):
# Arrange
input_string = "$ $ $ while (a == true) b = 1; $"
expected_output = False

# Act
write_to_file(self.SAMPLE_FILE_PATH, input_string)
actual_output = get_result_from_parser(self.SAMPLE_FILE_PATH)

# Assert
self.assertEqual(actual_output, expected_output)

if __name__ == '__main__':
unittest.main()

0 comments on commit 16e254d

Please sign in to comment.