corrige os erros existentes nestes ficheiros, para que seja gerada uma árvore sintática abstrata: mocp_tester.py from antlr4 import * from antlr4.tree.Tree import TerminalNode import sys import MocpLexer from MocpParser import MocpParser from mocpvisitor import MocpAstBuilder, printast from antlr4.error.ErrorListener import ErrorListener ========================= ERROS ========================= class MocpErrorListener(ErrorListener): def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): print(f"Erro sintático linha {line}, coluna {column}: {msg}") ========================= PARSE TREE ========================= def printparsetree(node, parser, indent=0): prefix = " " * indent if isinstance(node, TerminalNode): print(prefix + node.getText()) return if hasattr(node, "getRuleIndex"): print(prefix + parser.ruleNames[node.getRuleIndex()]) for i in range(node.getChildCount()): printparsetree(node.getChild(i), parser, indent + 2) ========================= MAIN ========================= def main(file): input_stream = FileStream(file, encoding="utf-8") lexer = MocpLexer.MocpLexer(input_stream) tokens = CommonTokenStream(lexer) parser = MocpParser(tokens) parser.removeErrorListeners() # Remove default error listeners parser.addErrorListener(MocpErrorListener()) # Add custom error listener tree = parser.program() print("\n================ PARSE TREE ================\n") printparsetree(tree, parser) print("\n================ AST ================\n") ast = MocpAstBuilder().visit(tree) print_ast(ast) if name == "main": if len(sys.argv) < 2: print("Uso: python mocptester.py <caminhodo_arquivo>") else: main(sys.argv[1]) mocp_visitor.py from antlr4 import * from MocpParserVisitor import MocpParserVisitor ========================================================= AST NODES ========================================================= class Node: def init(self, tipo): self.tipo = tipo self.filhos = [] class Program(Node): def init(self): super().init("Program") self.funcoes = [] self.variaveis = [] class Function(Node): def init(self, nome, retorno): super().init("Function") self.nome = nome self.retorno = retorno self.corpo = None class Id(Node): def init(self, name): super().init("Id") self.name = name class Lit(Node): def init(self, value): super().init("Lit") self.value = value class BinOp(Node): def init(self, op, left, right): super().init(f"Bin({op})") self.op = op self.left = left self.right = right class Return(Node): def init(self): super().init("Return") self.valor = None ========================================================= VISITOR ========================================================= class MocpAstBuilder(MocpParserVisitor): def visitProgram(self, ctx): p = Program() funcs = ctx.declaracaoFuncao() or [] vars_ = ctx.declaracaoVariavel() or [] for f in funcs: if f is not None: p.funcoes.append(self.visit(f)) for v in vars_: if v is not None: p.variaveis.append(self.visit(v)) return p def visitDeclaracaoFuncao(self, ctx): nome = ctx.ID().getText() if ctx.ID() else "main" retorno = ctx.tipo().getText() if ctx.tipo() else "void" f = Function(nome, retorno) if ctx.block(): f.corpo = self.visit(ctx.block()) return f def visitBlock(self, ctx): node = Node("Block") instrs = ctx.instrucao() or [] for instr in instrs: if instr is not None: node.filhos.append(self.visit(instr)) return node def visitInstrucao(self, ctx): atr = ctx.atribuicao() if atr: if isinstance(atr, list) and len(atr) == 0: return Node("EmptyAssign") return self.visit(atr) if ctx.RETORNAR(): r = Return() expr = ctx.expr() if expr: val = self.visit(expr) r.valor = val r.filhos.append(val) return r expr = ctx.expr() if expr: return self.visit(expr) return Node("Instrucao") def visitAtribuicao(self, ctx): node = Node("Assign") if ctx.ID(): node.filhos.append(Id(ctx.ID().getText())) if ctx.expr(): node.filhos.append(self.visit(ctx.expr())) return node def visitExpr(self, ctx): if ctx is None: return Node("EmptyExpr") Check for numeric literals and strings
corrige os erros existentes nestes ficheiros, para que seja gerada uma árvore sintática abstrata:
mocp_tester.py
from antlr4 import *
from antlr4.tree.Tree import TerminalNode
import sys
import MocpLexer
from MocpParser import MocpParser
from mocpvisitor import MocpAstBuilder, printast
from antlr4.error.ErrorListener import ErrorListener
=========================
ERROS
=========================
class MocpErrorListener(ErrorListener):
def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
print(f"Erro sintático linha {line}, coluna {column}: {msg}")
=========================
PARSE TREE
=========================
def printparsetree(node, parser, indent=0):
prefix = " " * indent
if isinstance(node, TerminalNode):
print(prefix + node.getText())
return
if hasattr(node, "getRuleIndex"):
print(prefix + parser.ruleNames[node.getRuleIndex()])
for i in range(node.getChildCount()):
printparsetree(node.getChild(i), parser, indent + 2)
=========================
MAIN
=========================
def main(file):
input_stream = FileStream(file, encoding="utf-8")
lexer = MocpLexer.MocpLexer(input_stream)
tokens = CommonTokenStream(lexer)
parser = MocpParser(tokens)
parser.removeErrorListeners() # Remove default error listeners
parser.addErrorListener(MocpErrorListener()) # Add custom error listener
tree = parser.program()
print("\n================ PARSE TREE ================\n")
printparsetree(tree, parser)
print("\n================ AST ================\n")
ast = MocpAstBuilder().visit(tree)
print_ast(ast)
if name == "main":
if len(sys.argv) < 2:
print("Uso: python mocptester.py <caminhodo_arquivo>")
else:
main(sys.argv[1])
mocp_visitor.py
from antlr4 import *
from MocpParserVisitor import MocpParserVisitor
=========================================================
AST NODES
=========================================================
class Node:
def init(self, tipo):
self.tipo = tipo
self.filhos = []
class Program(Node):
def init(self):
super().init("Program")
self.funcoes = []
self.variaveis = []
class Function(Node):
def init(self, nome, retorno):
super().init("Function")
self.nome = nome
self.retorno = retorno
self.corpo = None
class Id(Node):
def init(self, name):
super().init("Id")
self.name = name
class Lit(Node):
def init(self, value):
super().init("Lit")
self.value = value
class BinOp(Node):
def init(self, op, left, right):
super().init(f"Bin({op})")
self.op = op
self.left = left
self.right = right
class Return(Node):
def init(self):
super().init("Return")
self.valor = None
=========================================================
VISITOR
=========================================================
class MocpAstBuilder(MocpParserVisitor):
def visitProgram(self, ctx):
p = Program()
funcs = ctx.declaracaoFuncao() or []
vars_ = ctx.declaracaoVariavel() or []
for f in funcs:
if f is not None:
p.funcoes.append(self.visit(f))
for v in vars_:
if v is not None:
p.variaveis.append(self.visit(v))
return p
def visitDeclaracaoFuncao(self, ctx):
nome = ctx.ID().getText() if ctx.ID() else "main"
retorno = ctx.tipo().getText() if ctx.tipo() else "void"
f = Function(nome, retorno)
if ctx.block():
f.corpo = self.visit(ctx.block())
return f
def visitBlock(self, ctx):
node = Node("Block")
instrs = ctx.instrucao() or []
for instr in instrs:
if instr is not None:
node.filhos.append(self.visit(instr))
return node
def visitInstrucao(self, ctx):
atr = ctx.atribuicao()
if atr:
if isinstance(atr, list) and len(atr) == 0:
return Node("EmptyAssign")
return self.visit(atr)
if ctx.RETORNAR():
r = Return()
expr = ctx.expr()
if expr:
val = self.visit(expr)
r.valor = val
r.filhos.append(val)
return r
expr = ctx.expr()
if expr:
return self.visit(expr)
return Node("Instrucao")
def visitAtribuicao(self, ctx):
node = Node("Assign")
if ctx.ID():
node.filhos.append(Id(ctx.ID().getText()))
if ctx.expr():
node.filhos.append(self.visit(ctx.expr()))
return node
def visitExpr(self, ctx):
if ctx is None:
return Node("EmptyExpr")