Documentos de Académico
Documentos de Profesional
Documentos de Cultura
py
# -*- coding: utf-8 -*'''
Proyecto 4 - Parte 1
====================
Generacin de cdigo para HOC. En este proyecto, se va a convertir el
AST dentro de un cdigo de mquina intermedio conocido como Asignacin
Esttica nica (SSA - Single Static Assignment). Hay alguna partes
importantes que se necesitan saber para hacer este trabajo. Por favor,
lea cuidadosamente antes de iniciar:
2 + 3*4 - 5
int_1 = 2
int_2 = 3
int_3 = 4
int_4 = int_2 * int_3
int_5 = int_1 + int_4
int_6 = 5
int_7 = int_5 - int_6
En este cdigo, las variables int_n son simplemente temporales usadas durante
la realizacin de los clculos. Una caracterstica crtica de SSA es que
tales variables temporales slo se asignan una vez (asignacin nica) y nunca
se vuelve a utilizar. Por lo tanto, si se tuviera que evaluar otra expresin,
solo tendra que incrementar los nmeros. Por ejemplo, si se fuera a evaluar
10+20+30, se tendra un cdigo como este:
int_8 = 10
int_9 = 20
int_10 = int_8 + int_9
int_11 = 30
int_12 = int_11 + int_11
SSA est destinado a imitar las instrucciones de bajo nivel que se podran
llevar a cabo en una CPU. Por ejemplo, las instrucciones anteriores pueden
ser traducidas a instrucciones de mquina de bajo nivel (para una CPU
hipottica) de esta manera:
MOVI #2, R1
MOVI #3, R2
MOVI #4, R3
MUL
R2, R3, R4
ADD
R4, R1, R5
MOVI #5, R6
SUB
R5, R6, R7
[
('movi', 2, 'int_1'),
('movi', 3, 'int_2'),
('movi', 4, 'int_3'),
('mul', 'int_2', 'int_3', 'int_4'),
('add', 'int_1', 'int_4', 'int_5'),
('movi', 5, 'int_6'),
('sub', 'int_5','int_6','int_7'),
]
a = 10 + 20;
b = 2 * a;
a = a + 1;
int_1 = 10
int_2 = 20
a_1 = int_1 + int_2
int_3 = 2
b_1 = int_3 * a_1
int_4 = 1
a_2 = a_1 + int_4
...
Por rezones que tienen sentido despues, vamos a tratar a las variables
declaradas como localizaciones de memoria y acceder a ellas usando
instrucciones load/store. Por ejemplo:
int_1 = 10
int_2 = 20
int_3 = int_1 + int_2
store(int_3, "a")
int_4 = 2
int_5 = load("a")
int_6 = int_4 * int_5
store(int_6,"b")
int_7 = load("a")
int_8 = 1
int_9 = int_7 + int_8
store(int_9, "a")
2 + 3*4
2.0 + 3.0*4.0
(ints)
(floats)
('literal_int', 2, 'int_1')
('literal_int', 3, 'int_2')
('literal_int', 4, 'int_3')
('mul_int', 'int_2', 'int_3', 'int_4')
('add_int', 'int_1', 'int_4', 'int_5')
Su tarea
========
Su tarea es la siguiente: Escriba una clase Visitor() AST que tome un
programa en HOC y lo aplane a una nica secuencia de instrucciones
de cdigo de SSA representadas como tuplas de la forma
('alloc_type',varname)
target
('load_type', varname, target)
dentro de target
('store_type',source, varname)
de varname
('mul_type',left,right,target)
('div_type',left,right,target)
entero)
('uadd_type',source,target)
# target = +source
('uneg_type',source,target)
# target = -source
('print_type',source)
'''
import hocast
import hocblock
from hocblock import BasicBlock, IfBlock, WhileBlock
from collections import defaultdict
binary_ops = {
'+' : 'add',
'-' : 'sub',
'*' : 'mul',
'/' : 'div',
'<' : 'lt',
'>' : 'gt',
'==': 'eq',
'!=': 'ne',
'<=': 'le',
'>=': 'ge',
'&&': 'land',
'||': 'lor',
}
unary_ops = {
'+' : 'uadd',
'-' : 'usub',
'!' : 'lnot',
}
def new_temp(self,typeobj):
'''
Crea una nueva variable temporal de un tipo dado.
'''
name = "__%s_%d" % (typeobj.name, self.versions[typeobj.name])
self.versions[typeobj.name] += 1
return name
def visit_Literal(self,node):
# Crea un nuevo nombre de variable temporal
target = self.new_temp(node.type)
def visit_BinaryOp(self,node):
# Visita las expresiones izquierda y derecha
self.visit(node.left)
self.visit(node.right)
def visit_RelationalOp(self,node):
# Visit las expresiones izquierda y derecha
self.visit(node.left)
self.visit(node.right)
def visit_PrintStatement(self,node):
def visit_Program(self,node):
self.visit(node.program)
#def visit_Statements(self,node):
#
self.visit(node.expr)
self.code.append(inst)
#def visit_Statement(self,node):
#
self.visit(node.expr)
self.code.append(inst)
def visit_ConstDeclaration(self,node):
# localice en memoria
inst = ('alloc_'+node.type.name,
node.id)
self.code.append(inst)
# almacene valor inicial
self.visit(node.value)
inst = ('store_'+node.type.name,
node.value.gen_location,
node.id)
self.code.append(inst)
def visit_VarDeclaration(self,node):
# localice en memoria
inst = ('alloc_'+node.type.name,
node.id)
self.code.append(inst)
# almacene pot. val inicial
if node.value:
self.visit(node.value)
inst = ('store_'+node.type.name,
node.value.gen_location,
node.id)
self.code.append(inst)
def visit_LoadLocation(self,node):
target = self.new_temp(node.type)
inst = ('load_'+node.type.name,
node.name,
target)
self.code.append(inst)
node.gen_location = target
#def visit_Extern(self,node):
#
self.visit(node.expr)
self.code.append(inst)
#def visit_FuncPrototype(self,node):
#
self.visit(node.expr)
self.code.append(inst)
#def visit_Parameters(self,node):
#
self.visit(node.expr)
self.code.append(inst)
node.gen_location = target
#def visit_ParamDecl(self,node):
#
self.visit(node.expr)
self.code.append(inst)
def visit_AssignmentStatement(self,node):
self.visit(node.value)
inst = ('store_'+node.value.type.name,
node.value.gen_location,
node.location)
self.code.append(inst)
def visit_UnaryOp(self,node):
self.visit(node.left)
target = self.new_temp(node.type)
opcode = unary_ops[node.op] + "_" + node.left.type.name
inst = (opcode, node.left.gen_location)
self.code.append(inst)
node.gen_location = target
def visit_IfStatement(self,node):
if_block = IfBlock()
self.code.next_block = if_block
# condition
self.switch_block(if_block)
self.visit(node.condition)
if_block.test = node.condition.gen_location
# then branch
if_block.if_branch = BasicBlock()
self.switch_block(if_block.if_branch)
self.visit(node.then_b)
# else branch
if node.else_b:
if_block.else_branch = BasicBlock()
self.switch_block(if_block.else_branch)
self.visit(node.else_b)
# fija el siguiente bloque
if_block.next_block = BasicBlock()
self.switch_block(if_block.next_block)
def visit_Group(self,node):
self.visit(node.expression)
node.gen_location = node.expression.gen_location
#def visit_FunCall(self,node):
#
self.visit(node.expr)
self.code.append(inst)
#def visit_ExprList(self,node):
#
self.visit(node.expr)
self.code.append(inst)
# STEP 3: Probar
#
# Trate de correr este programa con un archivo adecuado para tal efecto y vea
# la secuencia del codigo SSA resultante.
#
#
#
# ---------------------------------------------------------------------#
# ---------------------------------------------------------------------def generate_code(node):
'''
Genera cdigo SSA desde el nodo AST entregado.
'''
gen = GenerateCode()
gen.visit(node)
return gen
if __name__ == '__main__':
import hoclex
import hocparse
import hoccheck
import sys
from errors import subscribe_errors, errors_reported
lexer = hoclex.make_lexer()
parser = hocparse.make_parser()
with subscribe_errors(lambda msg: sys.stdout.write(msg+"\n")):
program = parser.parse(open(sys.argv[1]).read())
# Revise el programa
hoccheck.check_program(program)
# Si no ocurre errore, genere cdigo
if not errors_reported():
code = generate_code(program)
# Emite la secuencia de cdigo
hocblock.PrintBlocks().visit(code.start_block)
#for inst in code.code:
#
print(inst)