Ejemplo n.º 1
0
def create_write(mod,ln=False):
	""" Creates a stub of println """
	
	if ln:
		fname = "writeln"
	else:
		fname = "write"
	printf = mod.get_function_named("printf")
	
	string_pointer = Type.pointer(types.int8, 0)
	
	f = mod.add_function(
		types.function(types.void, (string_pointer,) )
	, fname)
	bb = f.append_basic_block("entry")	
	builder = Builder.new(bb)
	builder.call(printf,   (
		f.args[0],
	))
	
	if ln:
		builder.call(printf,   (
			pointer(builder, c_string(mod,"\n")),
		))
	builder.ret_void()
	return f
Ejemplo n.º 2
0
def create_write(mod,ln=False):
	""" Creates a stub of println """
	
	if ln:
		fname = "writeln"
	else:
		fname = "write"
	printf = mod.get_function_named("printf")
	
	string_pointer = Type.pointer(types.int8, 0)
	
	f = mod.add_function(
		types.function(types.void, (string_pointer,) )
	, fname)
	bb = f.append_basic_block("entry")	
	builder = Builder.new(bb)
	builder.call(printf,   (
		f.args[0],
	))
	
	if ln:
		builder.call(printf,   (
			pointer(builder, c_string(mod,"\n")),
		))
	builder.ret_void()
	return f
Ejemplo n.º 3
0
def add_stdio(mod):
    """ Adds stdio functions to a module """
    return {
        "printf": mod.add_function(types.function(types.void, (Type.pointer(types.int8, 0),), 1), "printf"),
        "writeln": create_write(mod,ln=True),
        "write": create_write(mod),
        "writeint": create_write_alt('integer', mod)
    }
Ejemplo n.º 4
0
def add_stdio(mod):
	""" Adds stdio functions to a module """
	return {
		"printf": mod.add_function(types.function(types.void, (Type.pointer(types.int8, 0),), 1), "printf"),
		"writeln": create_write(mod,ln=True),
		"write": create_write(mod),
		"writeint": create_write_alt('integer',mod),
		"writereal": create_write_alt('real',mod),
		"writelnint": create_write_alt('integer',mod,ln=True),
		"writelnreal": create_write_alt('real',mod,ln=True)
	}
Ejemplo n.º 5
0
def add_stdio(mod):
    """ Adds stdio functions to a module """
    return {
        "printf": mod.add_function(types.function(types.void, (Type.pointer(types.int8, 0),), 1), "printf"),
        "println": create_print(mod,ln=True),
        "print": create_print(mod),
        "printint": create_print_alt('int',mod),
        "printreal": create_print_alt('real',mod),
        "printchar": create_print_alt('char',mod),
        "printbool": create_print_alt('bool',mod),
        "printlnint": create_print_alt('int',mod,ln=True),
        "printlnreal": create_print_alt('real',mod,ln=True),
        "printlnchar": create_print_alt('char',mod,ln=True),
        "printlnbool": create_print_alt('bool',mod,ln=True)
    }
Ejemplo n.º 6
0
	def __call__(self,ast):
		
		if ast.__class__ != Node:
			return ast
			
		if ast.type == "program":
			mod_name = self.descend(ast.args[0])
			if not mod_name:
				mod_name = "pascal_program"
			
			self.module = Module.new(mod_name)
			stdio = add_stdio(self.module)
			for f in stdio:
				self.functions[f] = stdio[f]
			
			main = create_main(self.module)
			
			block = Builder.new(main.append_basic_block("entry"))
			
			self.contexts.append(Context(main,block))
			self.descend(ast.args[1])
			
			self.get_builder().ret(c_int(0))
			
			return self.module
			
		elif ast.type == "block":

			self.descend(ast.args[0]) # Var
			self.descend(ast.args[1]) # Function def
			self.descend(ast.args[2]) # Statement
		
		elif ast.type in ["var_list","statement_list","function_list"]:
			for son in ast.args:
				self.descend(son)
				
		elif ast.type == "var":
			var_name = self.descend(ast.args[0])
			var_type_name = self.descend(ast.args[1])
			builder = self.get_builder()
			v = var_init(builder, var_name, var_type_name)
			self.set_var(var_name,v)
			
		elif ast.type == "type":
			return str(ast.args[0]).upper()
			
		elif ast.type == "identifier":
			return str(ast.args[0]).lower()
			
		elif ast.type in ["function_call","function_call_inline"]:
			builder = self.get_builder()
			
			function_name = self.descend(ast.args[0])
			
			arguments = []			
			if len(ast.args) > 1:
				if ast.args[1]:
					arguments = self.descend(ast.args[1])

			if function_name in ['write','writeln']:
				if str(arguments[0].type) == 'double':
					function_name += "real"
				elif str(arguments[0].type) == 'i32':
					function_name += "int"
				

			function = self.module.get_function_named(function_name)
			return builder.call(function,arguments)
			
		elif ast.type == "parameter_list":
			l = []
			l.extend(self.descend(ast.args[0]))
			l.extend(self.descend(ast.args[1]))
			return l
			
		elif ast.type == "parameter":
			c = ast.args[0]
			if c.type == "identifier":
				label = self.descend(ast.args[0])
				c = self.get_var(label)
			else:
				c = self.descend(ast.args[0])
			return [c]
			
		elif ast.type == "assign":
			builder = self.get_builder()
			varName = self.descend(ast.args[0])
			value = self.descend(ast.args[1])
			ref = self.get_var(varName)
			builder.store(value, ref)
			return varName
			
		elif ast.type in ['procedure','function']:
			
			def get_params(node):
				""" Return a list of tuples of params """
				if node.type == 'parameter':
					return [(self.descend(node.args[0]), types.translation[self.descend(node.args[1])])]
				else:
					l = []
					for p in node.args:
						l.extend(get_params(p))
					return l
				
			head = ast.args[0]
			if head.type == 'procedure_head':
				return_type = types.void
			else:
				return_type = types.translation[self.descend(head.args[-1])]
				
			name = self.descend(head.args[0])
			if len(head.args) > 1:
				params = get_params(head.args[1])
			else:
				params = []
			code = ast.args[1]
			
			ftype = types.function(return_type,[ i[1] for i in params ])
			f = Function.new(self.module, ftype, name)
			fb = Builder.new(f.append_basic_block("entry"))
			
			self.contexts.append(Context( f,fb ))
			b = self.get_builder()
			for i,p in enumerate(params):
				x = f.args[i]; x.name = p[0]
				self.set_param(p[0],x)
				
			if ast.type == 'function':
				type_name = types.reverse_translation[return_type]
				v = var_init(b, name, type_name)
				self.set_var(name,v)
			self.descend(code)
			b = self.get_builder()
			if ast.type == 'procedure':
				b.ret_void()
			else:
				b.ret(b.load(self.get_var(name)))
			self.contexts.pop()
		
        

		elif ast.type == "while":
			self.counter += 1
			now = self.get_function()
			builder = self.get_builder()
			
			
			loop = now.append_basic_block("loop_%d" % self.counter)			
			body = now.append_basic_block("body_%d" % self.counter)
			tail = now.append_basic_block("tail_%d" % self.counter)

			# do while code
			self.contexts.append(Context(loop))
			b = self.get_builder()
			cond = self.descend(ast.args[0])
			b.cbranch(cond,body,tail)
			self.contexts.pop()
			
			self.contexts.append(Context(body))
			b = self.get_builder()
			self.descend(ast.args[1])
			# repeat
			b.branch(loop)
			self.contexts.pop()
			
			# start loop
			builder.branch(loop)
			self.contexts[-1].builder = Builder.new(tail)
			
		elif ast.type == "repeat":
			cond = Node('not',ast.args[1])
			body = ast.args[0]
			
			while_b = Node('while',cond,body)
			final = Node('statement_list',body,while_b)
			return self.descend(final)
			
		elif ast.type == "for":
			
			direction = self.descend(ast.args[1])
			limit = ast.args[2]
			builder = self.get_builder()
			
			# var declaration
			varname = self.descend(ast.args[0].args[0])
			vartype = "INTEGER"
			v = var_init(builder, varname, vartype)
			self.set_var(varname,v)
			
			# var init
			variable = self.descend(ast.args[0])
			
			# cond
			var1 = Node('element',Node('identifier',varname))
			var1_name = Node('identifier',varname)

			sign = Node('sign',(direction == "to") and '<=' or '>=')
			comp = Node('op',sign,var1,limit)
			
			# body
			op = Node('sign',(direction == "to") and '+' or '-')
			varvalue = Node('op',op,var1,Node('element',Node('integer',1)))
			increment = Node('assign',var1_name,varvalue)
			
			body = Node('statement_list',ast.args[3],increment)
			
			# do while
			while_block = Node('while',comp,body)			
			
			self.descend(while_block)
			
			
		elif ast.type == "if":
			now = self.get_function()
			builder = self.get_builder()
			
			#if
			cond = self.descend(ast.args[0])
			
			# the rest
			self.counter += 1
			tail = now.append_basic_block("tail_%d" % self.counter)
			
			# then
			then_block = now.append_basic_block("if_%d" % self.counter)
			self.contexts.append( Context(then_block)  )
			self.descend(ast.args[1])
			b = self.get_builder()
			b.branch(tail)
			b.position_at_end(tail)
			self.contexts.pop()
			
			# else
			else_block = now.append_basic_block("else_%d" % self.counter)
			self.contexts.append( Context(else_block)  )
			if len(ast.args) > 2:
				self.descend(ast.args[2])
			b = self.get_builder()
			b.branch(tail)
			b.position_at_end(tail)
			self.contexts.pop()
			
			builder.cbranch(cond,then_block,else_block)
			self.contexts[-1].builder = Builder.new(tail)
				

		elif ast.type in ["sign","and_or"]:
			return ast.args[0]
			
		elif ast.type == 'not':
			v = self.descend(ast.args[0])
			builder = self.get_builder()
			return builder.not_(v)

		elif ast.type == "op":
			sign = self.descend(ast.args[0])
			v1 = self.descend(ast.args[1])
			v2 = self.descend(ast.args[2])
			
			builder = self.get_builder()
			
			if sign == "+":
				return builder.add(v1, v2)
			elif sign == "-":
				return builder.sub(v1, v2)
			elif sign == "*":
				return builder.mul(v1, v2)
			elif sign == "/":
				return builder.fdiv(v1, v2)
			elif sign == "div":
				return builder.sdiv(v1, v2)
			elif sign == "mod":
				return builder.urem(v1, v2)
			elif sign in [">",">=","=","<=","<","<>"]:
				return compare(sign,v1,v2,builder)
			elif sign == "and":
				return builder.and_(v1,v2)
			elif sign == "or":
				return builder.or_(v1,v2)
			else:
				print sign	
				
				
		elif ast.type == "element":
			builder = self.get_builder()
			
			e = ast.args[0]
			if e.type == "identifier":
				ref = self.get_var(self.descend(e))
				if ref.__class__ == Argument:
					return ref
				return builder.load(ref)
			else:
				return self.descend(ast.args[0])
			
		elif ast.type == "string":
			b = self.get_builder()
			s = c_string(self.module,ast.args[0])
			return pointer(b,s)
			
		elif ast.type == "integer":
			return c_int(int(ast.args[0]))
			
		elif ast.type == "real":
			return c_real(float(ast.args[0]))
			
		else:
			print "unknown:", ast.type
			sys.exit()
Ejemplo n.º 7
0
    def __call__(self, ast):

        if ast.__class__ != Node:
            return ast

        if ast.type == "program":
            mod_name = self.descend(ast.args[0])
            if not mod_name:
                mod_name = "pascal_program"

            self.module = Module.new(mod_name)
            stdio = add_stdio(self.module)
            for f in stdio:
                self.functions[f] = stdio[f]

            main = create_main(self.module)

            block = Builder.new(main.append_basic_block("entry"))

            self.contexts.append(Context(main, block))
            self.descend(ast.args[1])

            self.get_builder().ret(c_int(0))

            return self.module

        elif ast.type == "block":

            self.descend(ast.args[0])  # Var
            self.descend(ast.args[1])  # Function def
            self.descend(ast.args[2])  # Statement

        elif ast.type in ["var_list", "statement_list", "function_list"]:
            for son in ast.args:
                self.descend(son)

        elif ast.type == "var":
            var_name = self.descend(ast.args[0])
            var_type_name = self.descend(ast.args[1])
            builder = self.get_builder()
            v = var_init(builder, var_name, var_type_name)
            self.set_var(var_name, v)

        elif ast.type == "type":
            return str(ast.args[0]).upper()

        elif ast.type == "identifier":
            return str(ast.args[0]).lower()

        elif ast.type in ["function_call", "function_call_inline"]:
            builder = self.get_builder()

            function_name = self.descend(ast.args[0])

            arguments = []
            if len(ast.args) > 1:
                if ast.args[1]:
                    arguments = self.descend(ast.args[1])

            if function_name in ['write', 'writeln']:
                if str(arguments[0].type) == 'double':
                    function_name += "real"
                elif str(arguments[0].type) == 'i32':
                    function_name += "int"

            function = self.module.get_function_named(function_name)
            return builder.call(function, arguments)

        elif ast.type == "parameter_list":
            l = []
            l.extend(self.descend(ast.args[0]))
            l.extend(self.descend(ast.args[1]))
            return l

        elif ast.type == "parameter":
            c = ast.args[0]
            if c.type == "identifier":
                label = self.descend(ast.args[0])
                c = self.get_var(label)
            else:
                c = self.descend(ast.args[0])
            return [c]

        elif ast.type == "assign":
            builder = self.get_builder()
            varName = self.descend(ast.args[0])
            value = self.descend(ast.args[1])
            ref = self.get_var(varName)
            builder.store(value, ref)
            return varName

        elif ast.type in ['procedure', 'function']:

            def get_params(node):
                """ Return a list of tuples of params """
                if node.type == 'parameter':
                    return [(self.descend(node.args[0]),
                             types.translation[self.descend(node.args[1])])]
                else:
                    l = []
                    for p in node.args:
                        l.extend(get_params(p))
                    return l

            head = ast.args[0]
            if head.type == 'procedure_head':
                return_type = types.void
            else:
                return_type = types.translation[self.descend(head.args[-1])]

            name = self.descend(head.args[0])
            if len(head.args) > 1:
                params = get_params(head.args[1])
            else:
                params = []
            code = ast.args[1]

            ftype = types.function(return_type, [i[1] for i in params])
            f = Function.new(self.module, ftype, name)
            fb = Builder.new(f.append_basic_block("entry"))

            self.contexts.append(Context(f, fb))
            b = self.get_builder()
            for i, p in enumerate(params):
                x = f.args[i]
                x.name = p[0]
                self.set_param(p[0], x)

            if ast.type == 'function':
                type_name = types.reverse_translation[return_type]
                v = var_init(b, name, type_name)
                self.set_var(name, v)
            self.descend(code)
            b = self.get_builder()
            if ast.type == 'procedure':
                b.ret_void()
            else:
                b.ret(b.load(self.get_var(name)))
            self.contexts.pop()

        elif ast.type == "while":
            self.counter += 1
            now = self.get_function()
            builder = self.get_builder()

            loop = now.append_basic_block("loop_%d" % self.counter)
            body = now.append_basic_block("body_%d" % self.counter)
            tail = now.append_basic_block("tail_%d" % self.counter)

            # do while code
            self.contexts.append(Context(loop))
            b = self.get_builder()
            cond = self.descend(ast.args[0])
            b.cbranch(cond, body, tail)
            self.contexts.pop()

            self.contexts.append(Context(body))
            b = self.get_builder()
            self.descend(ast.args[1])
            # repeat
            b.branch(loop)
            self.contexts.pop()

            # start loop
            builder.branch(loop)
            self.contexts[-1].builder = Builder.new(tail)

        elif ast.type == "repeat":
            cond = Node('not', ast.args[1])
            body = ast.args[0]

            while_b = Node('while', cond, body)
            final = Node('statement_list', body, while_b)
            return self.descend(final)

        elif ast.type == "for":

            direction = self.descend(ast.args[1])
            limit = ast.args[2]
            builder = self.get_builder()

            # var declaration
            varname = self.descend(ast.args[0].args[0])
            vartype = "INTEGER"
            v = var_init(builder, varname, vartype)
            self.set_var(varname, v)

            # var init
            variable = self.descend(ast.args[0])

            # cond
            var1 = Node('element', Node('identifier', varname))
            var1_name = Node('identifier', varname)

            sign = Node('sign', (direction == "to") and '<=' or '>=')
            comp = Node('op', sign, var1, limit)

            # body
            op = Node('sign', (direction == "to") and '+' or '-')
            varvalue = Node('op', op, var1, Node('element', Node('integer',
                                                                 1)))
            increment = Node('assign', var1_name, varvalue)

            body = Node('statement_list', ast.args[3], increment)

            # do while
            while_block = Node('while', comp, body)

            self.descend(while_block)

        elif ast.type == "if":
            now = self.get_function()
            builder = self.get_builder()

            #if
            cond = self.descend(ast.args[0])

            # the rest
            self.counter += 1
            tail = now.append_basic_block("tail_%d" % self.counter)

            # then
            then_block = now.append_basic_block("if_%d" % self.counter)
            self.contexts.append(Context(then_block))
            self.descend(ast.args[1])
            b = self.get_builder()
            b.branch(tail)
            b.position_at_end(tail)
            self.contexts.pop()

            # else
            else_block = now.append_basic_block("else_%d" % self.counter)
            self.contexts.append(Context(else_block))
            if len(ast.args) > 2:
                self.descend(ast.args[2])
            b = self.get_builder()
            b.branch(tail)
            b.position_at_end(tail)
            self.contexts.pop()

            builder.cbranch(cond, then_block, else_block)
            self.contexts[-1].builder = Builder.new(tail)

        elif ast.type in ["sign", "and_or"]:
            return ast.args[0]

        elif ast.type == 'not':
            v = self.descend(ast.args[0])
            builder = self.get_builder()
            return builder.not_(v)

        elif ast.type == "op":
            sign = self.descend(ast.args[0])
            v1 = self.descend(ast.args[1])
            v2 = self.descend(ast.args[2])

            builder = self.get_builder()

            if sign == "+":
                return builder.add(v1, v2)
            elif sign == "-":
                return builder.sub(v1, v2)
            elif sign == "*":
                return builder.mul(v1, v2)
            elif sign == "/":
                return builder.fdiv(v1, v2)
            elif sign == "div":
                return builder.sdiv(v1, v2)
            elif sign == "mod":
                return builder.urem(v1, v2)
            elif sign in [">", ">=", "=", "<=", "<", "<>"]:
                return compare(sign, v1, v2, builder)
            elif sign == "and":
                return builder.and_(v1, v2)
            elif sign == "or":
                return builder.or_(v1, v2)
            else:
                print sign

        elif ast.type == "element":
            builder = self.get_builder()

            e = ast.args[0]
            if e.type == "identifier":
                ref = self.get_var(self.descend(e))
                if ref.__class__ == Argument:
                    return ref
                return builder.load(ref)
            else:
                return self.descend(ast.args[0])

        elif ast.type == "string":
            b = self.get_builder()
            s = c_string(self.module, ast.args[0])
            return pointer(b, s)

        elif ast.type == "integer":
            return c_int(int(ast.args[0]))

        elif ast.type == "real":
            return c_real(float(ast.args[0]))

        else:
            print "unknown:", ast.type
            sys.exit()
Ejemplo n.º 8
0
    def __call__(self,ast):
        if ast.__class__ != Node:
            return ast

        if ast.type == "program":
            mod_name = "algol_program"
            self.module = Module.new(mod_name)
            stdio = add_stdio(self.module)
            for f in stdio:
                self.functions[f] = stdio[f]

            main = create_main(self.module)

            block = Builder.new(main.append_basic_block("entry"))

            self.contexts.append(Context(main,block))
            self.descend(ast.args[0])

            self.get_builder().ret(c_int(0))

            return self.module

        elif ast.type in ["block", "statement", "array_list", "bound_pair_list", "switch_list", "formal_parameter_list",
                           "for_list", "for_list_element", "subscript_list",
                           "type_list","unlabeled_block","block_head", "compound_statement", "compound_tail",
                           "declaration", "formal_parameter_part", "unconditional_statement", "basic_statement",
                           "unlabelled_basic_statement", "boolean_expression"]:
            for son in ast.args:
                self.descend(son)

        elif ast.type in ["expression", "label"]:
            return self.descend( ast.args[0])

        elif ast.type == "designational_expression":
            if len(ast.args) == 1:
                return self.descend( ast.args[0])

        elif ast.type == "simple_designational_expression":
            return self.descend( ast.args[0])

        elif ast.type == "actual_parameter_part":
            return self.descend(ast.args[0])

        elif ast.type == "actual_parameter_list":
            builder = self.get_builder()
            if len(ast.args) == 1:
                var = self.descend(ast.args[0])
                if isinstance(var, str):
                    return [builder.load(self.get_var(var))]
                return [var]
            else:
                ls = list()
                ls.extend(self.descend(ast.args[0]))
                var = self.get_var( self.descend(ast.args[2]) )
                ls.append(var)
                return ls

        elif ast.type == "actual_parameter":
            return self.descend(ast.args[0])

        elif ast.type in ["function_designator", "procedure_statement"]:
            builder = self.get_builder()
            function_name = self.descend(ast.args[0])

            arguments = list()
            if ast.args[1]:
                arguments = self.descend(ast.args[1])

            function = self.module.get_function_named(function_name)
            return builder.call(function, arguments)

        elif ast.type == "boolean_expression":
            pass

        elif ast.type == "if_statement":
            return self.descend(ast.args[0].args[0]), self.descend(ast.args[1])

        elif ast.type == "conditional_statement":
            #if
            if ast.args[0].type == 'if_clause':
                now = self.get_function()
                builder = self.get_builder()
                cond, statement = self.descend(ast.args[0])
                self.counter += 1
                tail = now.append_basic_block("tail_%d" % self.counter)

                # then
                then_block = now.append_basic_block("if_%d" % self.counter)
                self.contexts.append( Context(then_block)  )
                b = self.get_builder()
                b.branch(tail)
                b.position_at_end(tail)
                self.contexts.pop()

                #else
                else_block = None
                if len(ast.args) == 2 and ast.args[1].type == "statement":
                    else_block = now.append_basic_block("else_%d" % self.counter)
                    self.contexts.append( Context(else_block)  )
                    self.descend(ast.args[1])
                    b = self.get_builder()
                    b.branch(tail)
                    b.position_at_end(tail)
                    self.contexts.pop()

                builder.cbranch(cond,then_block,else_block)
                self.contexts[-1].builder = Builder.new(tail)

        elif ast.type == "left_part_list":
            if len(ast.args) == 1:
                return [self.descend( ast.args[0] )]
            else:
                ls = list()
                ls.extend( self.descend(ast.args[0]) )
                ls.append( self.descend(ast.args[1]) )

        elif ast.type == "left_part":
            return self.descend(ast.args[0])

        elif ast.type == "variable":
            return self.get_var( self.descend(ast.args[0]) )

        elif ast.type == "simple_variable":
            return self.descend(ast.args[0])

        elif ast.type == "arithmetic_expression":
            if len(ast.args) == 1:
                return self.descend(ast.args[0])

        elif ast.type == "simple_arithmetic_expression":
            if len(ast.args) == 1:
                return self.term(ast.args[0])
            elif len(ast.args) == 2:
                builder = self.get_builder()
                if ast.args[0].args[0] == "+":
                    return builder.add(c_int(0), self.term(ast.args[1]))
                else:
                    return builder.sub(c_int(0), self.term(ast.args[1]))
            else:
                builder = self.get_builder()
                if ast.args[1].args[0] == "+":
                    return builder.add(self.descend(ast.args[0]), self.term(ast.args[2]))
                else:
                    return builder.sub(self.descend(ast.args[0]), self.term(ast.args[2]))

        #добавляем название переменных и их типы из type_declaration
        elif ast.type == "type_declaration":
            local_or_own_type = ast.args[0]
            if len(local_or_own_type.args) == 1:
                var_type = local_or_own_type.args[0].args[0]
            else:
                var_type = local_or_own_type.args[0].args[0] + local_or_own_type.args[0].args[1]

            builder = self.get_builder()
            type_list = self.flatten(ast.args[1])
            for var_name in type_list:
                v = var_init(builder, var_name.args[0], var_type)
                self.set_var(var_name.args[0], v)


        elif ast.type in ["array_identifier", "variable_identifier", "procedure_identifier", "identifier"]:
            return str(ast.args[0]).lower()


        #присваивание
        elif ast.type == "assignment_statement":
            builder = self.get_builder()
            varName = self.descend(ast.args[0])
            value = self.descend(ast.args[1])
            for v in varName:
                ref = self.get_var(v)
                builder.store(value, ref)
            return varName[0]

        elif ast.type == "identifier_list":
            if len(ast.args) == 1:
                return [ast.args[0]]
            else:
                ls = list()
                ls.extend( self.descend(ast.args[0]) )
                ls.append( ast.args[2] )

        elif ast.type == "type":
            return types.translation[ast.args[0]]

        elif ast.type == "specifier":
            if len(ast.args) == 1:
                return self.descend(ast.args[0])

        elif ast.type == "specification_part":
            if len(ast.args) == 2:
                specifier = self.descend(ast.args[0])
                identifiers = self.descend(ast.args[1])
                return [(specifier, identifiers)]
            else:
                ls = list()
                ls.extend( self.descend(ast.args[0]) )
                ls.append( (self.descend(ast.args[1]), self.descend(ast.args[2]) ) )
                return ls


        #объявление процедур. Храним название процедур(перегрузку запрещаем)
        elif ast.type == "procedure_declaration":
            type = None
            if len(ast.args) > 2:
                type = ast.args[0].args[0]
                heading = ast.args[1]
                body = ast.args[2]
            else:
                heading = ast.args[0]
                body = ast.args[1]

            if not type:
                return_type = types.void
            else:
                return_type = types.translation[type]

            proc_name = heading.args[0].args[0].lower()


            args = list()
            value_part = list()
            specification_part = list()
            if len(heading.args) > 1:
                i = 1
                while i < len(heading.args):
                    if heading.args[i] is not None:
                        if heading.args[i].type == "formal_parameter_part":
                            if len(heading.args[i].args) > 0:
                                formal_parameter = heading.args[i].args[0]
                                if len(formal_parameter.args) > 0:
                                    args = self.flatten(formal_parameter.args[0])
                        elif heading.args[i].type == "value_part":
                            value_part = heading.args[i]
                            if len(value_part.args) > 0:
                                value_part = self.flatten(value_part.args[0])
                        elif heading.args[i].type == "specification_part":
                            specification_part = self.descend(heading.args[i])
                    i += 1

            code = body

            param_types = list()
            for arg in args:
                for type, var_names in specification_part:
                    if arg in var_names:
                        param_types.append(type)
                        break


            ftype = types.function(return_type,param_types)  #типы заранее мы не знаем
            f = Function.new(self.module, ftype, proc_name)
            fb = Builder.new(f.append_basic_block("entry"))

            self.contexts.append(Context( f,fb ))
            b = self.get_builder()
            for i, p in enumerate(args):
                x = f.args[i]
                x.name = p
                self.set_param(p, x)

            type_name = types.reverse_translation[return_type]
            v = var_init(b, proc_name, type_name)
            self.set_var(proc_name,v)
            self.descend(code)
            b = self.get_builder()
            b.ret(b.load(self.get_var(proc_name)))
            self.contexts.pop()


        elif ast.type == "while":
            self.counter += 1
            now = self.get_function()
            builder = self.get_builder()


            loop = now.append_basic_block("loop_%d" % self.counter)            
            body = now.append_basic_block("body_%d" % self.counter)
            tail = now.append_basic_block("tail_%d" % self.counter)

            # do while code
            self.contexts.append(Context(loop))
            b = self.get_builder()
            cond = self.descend(ast.args[0])
            b.cbranch(cond,body,tail)
            self.contexts.pop()

            self.contexts.append(Context(body))
            b = self.get_builder()
            self.descend(ast.args[1])
            # repeat
            b.branch(loop)
            self.contexts.pop()

            # start loop
            builder.branch(loop)
            self.contexts[-1].builder = Builder.new(tail)

        elif ast.type == "repeat":
            cond = Node('not',ast.args[1])
            body = ast.args[0]

            while_b = Node('while',cond,body)
            final = Node('statement_list',body,while_b)
            return self.descend(final)

        elif ast.type == "for":

            direction = self.descend(ast.args[1])
            limit = ast.args[2]
            builder = self.get_builder()

            # var declaration
            varname = self.descend(ast.args[0].args[0])
            vartype = "INTEGER"
            v = var_init(builder, varname, vartype)
            self.set_var(varname,v)

            # var init
            variable = self.descend(ast.args[0])

            # cond
            var1 = Node('element',Node('identifier',varname))
            var1_name = Node('identifier',varname)

            sign = Node('sign',(direction == "to") and '<=' or '>=')
            comp = Node('op',sign,var1,limit)

            # body
            op = Node('sign',(direction == "to") and '+' or '-')
            varvalue = Node('op',op,var1,Node('element',Node('integer',1)))
            increment = Node('assign',var1_name,varvalue)

            body = Node('statement_list',ast.args[3],increment)

            # do while
            while_block = Node('while',comp,body)            

            self.descend(while_block)


        elif ast.type in ["sign","and_or"]:
            return ast.args[0]

        elif ast.type == 'not':
            v = self.descend(ast.args[0])
            builder = self.get_builder()
            return builder.not_(v)


        elif ast.type == "element":
            builder = self.get_builder()

            e = ast.args[0]
            if e.type == "identifier":
                ref = self.get_var(self.descend(e))
                if ref.__class__ == Argument:
                    return ref
                return builder.load(ref)
            else:
                return self.descend(ast.args[0])

        elif ast.type == "string":
            b = self.get_builder()
            s = c_string(self.module,ast.args[0])
            return pointer(b,s)

        elif ast.type == "unsigned_number":
            if len(ast.args) == 1:
                return self.descend(ast.args[0])
            else:
                exp = self.descend(ast.args[1])
                return self.descend(ast.args[0]) * pow(x=10, y=exp)

        elif ast.type == "decimal_number":
            if len(ast.args) == 1:
                return self.descend(ast.args[0])
            else:
                return self.descend(ast.args[0]) + self.descend(ast.args[1])

        elif ast.type == "unsigned_integer":
            if len(ast.args) == 1:
                return c_int(int(ast.args[0]))
            else:
                value = self.descend(ast.args[0]) * 10 + ast.args[1]
                return c_int(int(ast.args[0]))

        elif ast.type == "real":
            return c_real(float(ast.args[0]))

        else:
            print "unknown:", ast.type
            sys.exit()
Ejemplo n.º 9
0
    def __call__(self, ast):
        if ast.__class__ != Node:
           return ast

        # PROGRAM
        if ast.type == "program": # Ínicio do programa
            self.module = Module.new("scurry") # Criar o módulo (string é um ID)
            # Os módulos LLVM são contentores. É preciso criá-lo antes de se poderem
            # adicionar variáveis globais, funções, etc.
            # Ver: http://mdevan.nfshost.com/llvm-py/userguide.html

            stdio = add_stdio(self.module)
            for f in stdio:
                self.functions[f] = stdio[f]

            main = create_main(self.module)

            block = Builder.new(main.append_basic_block("entry"))

            self.context_stack.push(Context(main,block))
            self.descend(ast.args[0]) # Variáveis globais, funções e procedimentos
            self.descend(ast.args[1]) # Main

            self.get_builder().ret(c_int(0))
            return self.module

        # PROC-FUNC-AND-VAR-LIST, STATEMENT-LIST
        elif ast.type in ["proc_func_and_var_list","statement_list"]:
            for son in ast.args:
                self.descend(son)

        # VAR
        elif ast.type == "var": # Declaração de variáveis
            var_type_name = self.descend(ast.args[0])
            var_name = self.descend(ast.args[1])
            builder = self.get_builder()
            v = var_init(self.module, builder, var_name, var_type_name)
            self.set_var(var_name,v)

        # GLOBAL-VAR
        elif ast.type == "global_var": # Declaração de variáveis globais
            var_type_name = self.descend(ast.args[0])
            var_name = self.descend(ast.args[1])
            builder = self.get_builder()
            v = global_var_init(self.module, var_type_name, var_name)

        # TYPE
        elif ast.type == "type":
            return str(ast.args[0])

        # IDENTIFIER
        elif ast.type == "identifier":
            return str(ast.args[0])

        # FUNCTION-CALL, FUNCTION-CALL-INLINE
        elif ast.type in ["function_call","function_call_inline"]:
            builder = self.get_builder()
            function_name = self.descend(ast.args[0])

            arguments = []
            if len(ast.args) > 1:
                if ast.args[1]:
                    arguments = self.descend(ast.args[1])

            if function_name in ['print','println']:
                if str(arguments[0].type) == 'double':
                    function_name += "real"
                elif str(arguments[0].type) == 'i32':
                    function_name += "int"
                elif str(arguments[0].type) == 'i8':
                    function_name += "char"
                elif str(arguments[0].type) == 'i1':
                    function_name += "bool"

            function = self.module.get_function_named(function_name)
            return builder.call(function,arguments)

        # PARAMETER-LIST
        elif ast.type == "parameter_list":
            l = []
            l.extend(self.descend(ast.args[0]))
            l.extend(self.descend(ast.args[1]))
            return l

        # PARAMETER
        elif ast.type == "parameter":
            c = ast.args[0]
            if c.type == "identifier":
                label = self.descend(ast.args[0])
                c = self.get_var(label)
            else:
                c = self.descend(ast.args[0])
            return [c]

        # ASSIGN
        elif ast.type == "assign":
            builder = self.get_builder()
            varName = self.descend(ast.args[0])
            value = self.descend(ast.args[1])

            (ref, isGlobal) = self.get_var(varName)
            if not isGlobal: # Variáveis locais
                # self.set_var(value, ref)
                builder.store(value, ref)
            else: # Variáveis globais
                ref.initializer = value
            return varName

        # VAR-ASSIGN
        elif ast.type == "var_assign":
            var_type_name = self.descend(ast.args[0])
            var_name = self.descend(ast.args[1])
            value = self.descend(ast.args[2])

            builder = self.get_builder()
            v = var_init(self.module, builder, var_name, var_type_name)
            self.set_var(var_name,v)
            if var_type_name != 'string':
                builder.store(value, v)

        # PROCEDURE, FUNCTION
        elif ast.type in ['procedure','function']:

            def get_params(node):
                """ Return a list of tuples of params """
                if node.type == 'parameter':
                    return [(self.descend(node.args[0]), types.translation[self.descend(node.args[1])])]
                else:
                    l = []
                    for p in node.args:
                        l.extend(get_params(p))
                    return l

            head = ast.args[0]
            if head.type == 'procedure_head':
                return_type = types.void
            else:
                return_type = types.translation[self.descend(head.args[-1])]

            name = self.descend(head.args[0])

            if ast.type == 'procedure' and len(head.args) == 1: # Apenas o nome
                params = [] # Nos procedimentos sem parâms é só nome que é posto na AST
            elif ast.type == 'function' and len(head.args) == 2: # Nome e tipo
                params = [] # Nas funções sem parâmetros, é só nome e tipo de retorno
            else:
                params = get_params(head.args[1])
            code = ast.args[1]

            ftype = types.function(return_type, [ i[1] for i in params ])
            f = Function.new(self.module, ftype, name)
            fb = Builder.new(f.append_basic_block("entry"))

            self.context_stack.push(Context(f, fb))
            b = self.get_builder()
            for i,p in enumerate(params):
                x = f.args[i]; x.name = p[0]
                type_name = types.reverse_translation[x.type]
                v = var_init(self.module, b, x.name, type_name)
                self.set_param(p[0],v)
                b.store(x, v)

            if ast.type == 'function': # Criar uma variável para guardar o retorno
                type_name = types.reverse_translation[return_type]
                v = var_init(self.module, b, 'result', type_name)
                self.set_var('result',v)
            self.descend(code)
            b = self.get_builder()
            if ast.type == 'procedure':
                b.ret_void()
            else:
                (ref, isGlobal) = self.get_var('result')
                b.ret(b.load(ref))
            self.context_stack.pop()

        # WHILE
        elif ast.type == "while":
            self.counter += 1
            now = self.get_function()
            builder = self.get_builder()

            loop = now.append_basic_block("loop_%d" % self.counter)
            body = now.append_basic_block("body_%d" % self.counter)
            tail = now.append_basic_block("tail_%d" % self.counter)

            # do while code
            self.context_stack.push(Context(loop))
            b = self.get_builder()
            cond = self.descend(ast.args[0])
            b.cbranch(cond,body,tail)
            self.context_stack.pop()

            self.context_stack.push(Context(body))
            b = self.get_builder()
            self.descend(ast.args[1])
            # repeat
            b.branch(loop)
            self.context_stack.pop()

            # start loop
            builder.branch(loop)
            self.context_stack.top().builder = Builder.new(tail)

        # DO
        elif ast.type == "do":
            cond = Node('not',ast.lineno,ast.args[1])
            body = ast.args[0]

            while_b = Node('while',ast.lineno,cond,body)
            final = Node('statement_list',ast.lineno,body,while_b)
            return self.descend(final)

        # FOR
        elif ast.type == "for":
            direction = self.descend(ast.args[1]) # Se é TO ou DOWNTO
            limit = ast.args[2] # O extremo direito a atingir

            if len(ast.args) == 5: # Se consiste em for com incremento diferente de 1
                inc = int(ast.args[4].args[0].args[0]) # Valor de incremento
            else: inc = 1

            builder = self.get_builder()

            # Declaração da variável contador
            varname = self.descend(ast.args[0].args[0])
            vartype = "int"
            v = var_init(self.module, builder, varname, vartype)
            self.set_var(varname,v)

            # var init
            variable = self.descend(ast.args[0])

            # cond
            var1 = Node('element',ast.lineno,Node('identifier',ast.lineno,varname))
            var1_name = Node('identifier',ast.lineno,varname)

            # body
            if (direction == "to" and inc > 0) or (direction == "downto" and inc < 0):
                sign_term = '<='
                op_term   = '+'
            elif (direction == "to" and inc < 0) or (direction == "downto" and inc > 0):
                sign_term = '>='
                op_term   = '-'
            else: raise_exception("Invalid increment value on 'for' statement")

            sign = Node('sign',ast.lineno,sign_term)
            op = Node('sign',ast.lineno,op_term)
            comp = Node('op',ast.lineno,sign,var1,limit)

            varvalue = Node('op',ast.lineno,op,var1,Node('element',ast.lineno,Node('int',ast.lineno,abs(inc))))
            increment = Node('assign',ast.lineno,var1_name,varvalue)
            body = Node('statement_list',ast.lineno,ast.args[3],increment)

            # do while
            while_block = Node('while',ast.lineno,comp,body)

            self.descend(while_block)

        # IF
        elif ast.type == "if":
            now = self.get_function()
            builder = self.get_builder()

            #if
            cond = self.descend(ast.args[0])

            # the rest
            self.counter += 1
            tail = now.append_basic_block("tail_%d" % self.counter)

            # then
            then_block = now.append_basic_block("if_%d" % self.counter)
            self.context_stack.push( Context(then_block)  )
            self.descend(ast.args[1])
            b = self.get_builder()
            b.branch(tail)
            b.position_at_end(tail)
            self.context_stack.pop()

            # else
            else_block = now.append_basic_block("else_%d" % self.counter)
            self.context_stack.push( Context(else_block)  )
            if len(ast.args) > 2:
                self.descend(ast.args[2])
            b = self.get_builder()
            b.branch(tail)
            b.position_at_end(tail)
            self.context_stack.pop()

            builder.cbranch(cond,then_block,else_block)
            self.context_stack.top().builder = Builder.new(tail)

        # UNLESS
        elif ast.type == "unless":
            # Transformar a condição 'unless' num 'if'
            cond = self.descend(ast.args[1])
            neg_cond = Node('not',ast.lineno,cond)
            node = Node('if',ast.lineno,neg_cond,ast.args[0])
            self.descend(node)

        # SIGN, AND-OR
        elif ast.type in ["sign","and_or"]:
            return ast.args[0]

        # OP
        elif ast.type == "op":
            sign = self.descend(ast.args[0])
            v1 = self.descend(ast.args[1])
            v2 = self.descend(ast.args[2])

            builder = self.get_builder()

            if sign == "+":
                return builder.add(v1, v2)
            elif sign == "-":
                return builder.sub(v1, v2)
            elif sign == "*":
                return builder.mul(v1, v2)
            # elif sign == "**":
            #     print "v1", v1
            #     print "v2", v2
            #     base = ast.args[1].args[0].args[0] # Base
            #     exp  = ast.args[2].args[0].args[0] # Expoente
            #     print "base", base
            #     print "exp", exp
            #     if ast.args[1].args[0].type == 'int':
            #         return c_int(int(base) ** int(exp))
            #     else: # Ambos base e expoente são float
            #         return c_real(float(base) ** float(exp))
            elif sign == "/" and str(v1.type) == 'i32' and str(v2.type) == 'i32':
                return builder.sdiv(v1, v2) # Divisão de inteiros
            elif sign == "/": # Divisão de floats
                return builder.fdiv(v1, v2)
            elif sign in ["mod", "%"]:
                return builder.urem(v1, v2)
            elif sign in [">",">=","==","<=","<","<>"]:
                return compare(sign,v1,v2,builder)
            elif sign == "and":
                return builder.and_(v1,v2)
            elif sign == "or":
                return builder.or_(v1,v2)
            else:
                raise_exception("undefined operator %s" % sign)

        # ELEMENT
        elif ast.type == "element":
            builder = self.get_builder()

            e = ast.args[0]
            if e.type == "identifier":
                var_name = ast.args[0].args[0] # Nome da variável
                (ref, isGlobal) = self.get_var(self.descend(e))
                if isGlobal:
                    return ref.initializer
                elif ref.__class__ == Argument:
                    return ref
                return builder.load(ref)
            else:
                return self.descend(ast.args[0])

        # NOT
        elif ast.type == 'not':
            # O nó é do tipo Node('not',ln(p),p[2]) logo p[2] == ast.args[0]
            v = self.descend(ast.args[0]) # A expressão a ser negada
            return self.get_builder().not_(v) # Negação da expressão v

        # STRING
        elif ast.type == "string":
            b = self.get_builder()
            s = c_string(self.module, ast.args[0])
            return pointer(b,s)

        # INT
        elif ast.type == "int":
            return c_int(int(ast.args[0]))

        # REAL
        elif ast.type == "real":
            return c_real(float(ast.args[0]))

        # CHAR
        elif ast.type == "char":
            char = ast.args[0][1] # Preciso [1] prq vem 'a' e queremos a (sem plicas)
            return c_char(char)

        # BOOL
        elif ast.type == "bool":
            if ast.args[0] == "false":
                return c_bool(False)
            else:
                return c_bool(True)

        else: # Se for encontrado um outro tipo de nó inesperado (só acontece se o
            # rules.py foi modificado)
            raise_exception("unknown: %s" % ast.type)