E → E + T | T
E → T E'
E' → + T E' | ε
E → T E'
E' → + T E' | ε
T → F T'
T' → * F T' | ε
F → ( E ) | id
E → T E'
E' → + T E' | ε
T → F T'
T' → * F T' | ε
F → ( E ) | id
class Parser:
def __init__(self, tokens):
self.tokens = tokens
self.pos = 0
self.lookahead = tokens[0]
def match(self, expected):
if self.lookahead == expected:
self.pos += 1
if self.pos < len(self.tokens):
self.lookahead = self.tokens[self.pos]
else:
self.error(f"Esperado {expected}")
def error(self, message):
raise Exception(message)
def parse(self):
self.expr()
if self.pos < len(self.tokens):
self.error("Tokens extras após fim da expressão")
# Para a gramática:
# E → T E'
# E' → + T E' | ε
# T → F T'
# T' → * F T' | ε
# F → ( E ) | id
def expr(self):
self.term()
self.expr_prime()
def expr_prime(self):
if self.lookahead == '+':
self.match('+')
self.term()
self.expr_prime()
# ε caso (não precisa fazer nada)
def term(self):
self.factor()
self.term_prime()
def term_prime(self):
if self.lookahead == '*':
self.match('*')
self.factor()
self.term_prime()
# ε caso
def factor(self):
if self.lookahead == '(':
self.match('(')
self.expr()
self.match(')')
elif self.lookahead == 'id':
self.match('id')
else:
self.error("Esperado '(' ou 'id'")
expr → term { ('+' | '-') term }
term → factor { ('*' | '/') factor }
factor → number | '(' expr ')'
def expr(self):
# Primeiro reconhece um term
self.term()
# Depois processa sequência de + ou - seguidos de term
while self.lookahead in ('+', '-'):
operator = self.lookahead
self.match(operator)
self.term()
# Aqui poderia adicionar código para
# construir a árvore ou avaliar a expressão
self.lookahead = self.tokens[self.pos]
def match(self, expected):
if self.lookahead == expected:
self.pos += 1
if self.pos < len(self.tokens):
self.lookahead = self.tokens[self.pos]
else:
self.lookahead = '$' # Fim da entrada
else:
self.error(f"Esperado {expected}, encontrado {self.lookahead}")
def tokenize(text):
tokens = []
i = 0
while i < len(text):
# Ignora espaços em branco
if text[i].isspace():
i += 1
continue
# Operadores e parênteses
if text[i] in "+-*/()":
tokens.append(text[i])
i += 1
continue
# Números
if text[i].isdigit():
start = i
while i < len(text) and text[i].isdigit():
i += 1
tokens.append(int(text[start:i]))
continue
# Caractere desconhecido
raise Exception(f"Caractere inválido: {text[i]}")
return tokens
def error(self, message):
line = self.get_current_line()
column = self.get_current_column()
error_message = f"Erro sintático na linha {line}, coluna {column}: {message}"
# Exibir o contexto do erro
line_content = self.get_line_content(line)
pointer = ' ' * (column - 1) + '^'
print(error_message)
print(line_content)
print(pointer)
raise SyntaxError(error_message)
def expr(self):
# Primeiro reconhece um term
left = self.term()
# Depois processa sequência de + ou - seguidos de term
while self.lookahead in ('+', '-'):
operator = self.lookahead
self.match(operator)
right = self.term()
# Cria um nó para a operação binária
left = Node('BinOp', operator, [left, right])
return left
expr → term { '+' term }
term → factor { '*' factor }
factor → number | '(' expr ')'
class Parser:
def __init__(self, tokens):
self.tokens = tokens
self.pos = 0
self.lookahead = tokens[0]
def match(self, expected):
# Implementar
def expr(self):
# Implementar
def term(self):
# Implementar
def factor(self):
# Implementar
expr → term { ('+' | '-') term }
term → factor { ('*' | '/') factor }
factor → number | '(' expr ')'
stmt → if_stmt | other_stmt
if_stmt → 'if' '(' expr ')' stmt ['else' stmt]
expr → 'true' | 'false'
other_stmt → 'A' | 'B'
# Problema: recursão à esquerda
expr → expr + term | term
# Solução
expr → term expr'
expr' → + term expr' | ε
# Problema: ambiguidade no if-else
stmt → if expr then stmt | if expr then stmt else stmt
# Solução
stmt → matched_stmt | unmatched_stmt
matched_stmt → if expr then matched_stmt else matched_stmt | other_stmt
unmatched_stmt → if expr then stmt | if expr then matched_stmt else unmatched_stmt