如何在PLY中正确实现抽象语法树?

How to Properly Implement an Abstract Syntax Tree in PLY?

提问人:Ackeem Mclennon 提问时间:11/17/2023 更新时间:11/17/2023 访问量:12

问:

嗨,大家好,我对编译器设计比较陌生,我正在寻求一些关于创建 AST 以及在树上执行语义检查和代码生成的帮助。请参阅下面我的解析器的源代码。还要注意。我的词法分析器的实现工作正常,所以我选择省略它。


import ply.yacc as yacc
from adapscriptlexer import tokens
from Node import*

precedence = (
    ('nonassoc','GE', 'LE', 'EQ', 'NE', 'GT', 'LT', 'OR'),
    ('left', 'ADD', 'SUB'),
    ('left', 'MUL', 'DIV'),
    ('right', 'UNARY')
)


def p_program(p):
    '''program : programStart'''
    p[0] = p[1]

def p_programStart(p):
    '''programStart : FUNC INIT "(" ")" "{" statements "}" '''
    
def p_statements(p):
    '''statements : statement
                | statements statement
                '''
    
                 
def p_statement(p):
    '''statement : function_calls
                | condition
                | function_declarations
                | expression
                | loops
                | RETURN expression
                | PRINT "(" expression ")"
                | assignment
                '''
                
                
def p_function_declarations(p):
        '''function_declarations : function_declaration'''

def p_function_declaration(p):
        '''function_declaration : FUNC IDENTIFIER "(" ")" ":" datatype "{" function_body "}" '''
        

def p_function_body(p):
        '''function_body : statements'''

def p_function_calls(p):
    '''function_calls : IDENTIFIER "(" ")"
                     | IDENTIFIER "(" ")" function_calls
                     | IDENTIFIER "(" parameters ")" 
                     | IDENTIFIER "(" parameters ")" function_calls'''
                     
def p_parameters(p):
    '''parameters : parameterList'''

def p_parameterList(p):
    '''parameterList : parameter
                    | parameter "," parameterList'''

def p_parameter(p):
    '''parameter : datatype IDENTIFIER'''

def p_datatype(p):
        '''datatype : INT
                    | FLOAT
                    | STRING
                    | ADAPT
                    | VOID'''
                    

def p_expression(p):
        '''expression : atoms
                    | paren_expr
                    | binary_expr'''
            
def p_atom(p):
        '''atoms : INT_VALUE
                | FLOAT_VALUE
                | STRING_VALUE
                | variable'''
                
def p_variable(p):
    '''variable : IDENTIFIER '''

def p_paren_expr(p):
        '''paren_expr : "(" expression ")"'''

def p_binary_expr(p):
        '''binary_expr : atoms ADD expression
                    | atoms SUB expression
                    | atoms MUL expression
                    | atoms DIV expression
                    | atoms OR expression
                    | atoms LE expression
                    | atoms GE expression
                    | atoms EQ expression
                    | atoms NE expression
                    | atoms GT expression
                    | atoms LT expression
                    | UNARY atoms
                    | atoms UNARY'''
        p[0] = BinOpNode(p[2], p[1], p[3])
                    
def p_assignment(p):    
        '''assignment : datatype IDENTIFIER EQUAL expression 
                      | datatype IDENTIFIER EQUAL ACCEPT "(" ")" '''

def p_condition(p):
        '''condition : IF expression "{" statements "}"
                    | IF expression "{" statements "}" ELSE "{" statements "}"'''

def p_loops(p):
        '''loops : loop
                | loop loops'''
        

def p_loop(p):
        '''loop : forLoop
                | whileLoop'''
        

def p_forLoop(p):
        '''forLoop : FOR "(" expression ";" condition ";" expression ")" "{" statements "}"'''
    
def p_whileLoop(p):
        '''whileLoop : WHILE "(" condition ")" "{" statements "}"'''

def p_error(p):
    print(f"Syntax error at line {p.lineno}, position {p.lexpos}: Unexpected token '{p.value}'")
   
   

parser = yacc.yacc( debug=True)
try:
    input = open("input3.txt", "r") 
except EOFError:
    print("End of file Error")
result = parser.parse(input.read())



if result is not None:
        print(result)    
    
    
    

我有一个 Node 的实用程序类,理论上应该为各种操作创建节点并评估这些节点:

    def __init__(self, type, children=None, leaf=None):
        self.type = type
        if children:
            self.children = children
        else:
            self.children = []
        self.leaf = leaf

    def semantic_analysis(self):
        raise NotImplementedError("Subclass must implement semantic_analysis")
    
class BinOpNode(Node):
    def __init__(self, operator, left, right):
        super().__init__('binop', children=[left, right], leaf=operator)

    def semantic_analysis(self):
        # Perform semantic analysis on the operands
        for child in self.children:
            child.semantic_analysis()

        # Check that the operands are of the correct type
        left_type = type(self.children[0].leaf)
        right_type = type(self.children[1].leaf)

        if self.leaf in ['ADD', 'SUB', 'MUL', 'DIV']:
            if not (left_type in [int, float] and right_type in [int, float]):
                raise TypeError("Operands must be integers or floats for arithmetic operations")
        elif self.leaf in ['GE', 'LE', 'EQ', 'NE', 'GT', 'LT']:
            if not (left_type == right_type):
                raise TypeError("Operands must be of the same type for comparison operations")

    def evaluate(self):
            left_value = self.children[0].evaluate()
            right_value = self.children[1].evaluate()

            if self.leaf == 'ADD':
                return left_value + right_value
            elif self.leaf == 'SUB':
                return left_value - right_value
            elif self.leaf == 'MUL':
                return left_value * right_value
            elif self.leaf== 'DIVIDE':
                if right_value != 0:
                    return left_value / right_value
                else:
                    raise ValueError("Division by zero")


到目前为止,我只设法实现了二进制操作。任何见解和帮助将不胜感激。

python 解析 编译器-构造 词法分析器 ply

评论


答: 暂无答案