PLY: некоторые производные / грамматические правила не запускаются, что приводит к синтаксической ошибке - PullRequest
0 голосов
/ 03 марта 2019

Я использую PLY для анализа программы на C только с помощью конструкции for.Проблема, с которой я столкнулся, заключается в том, что моя программа, похоже, принимает только определенные формы / случаи цикла for, что приводит к синтаксической ошибке для других, хотя я написал деривации для тех, на которых программа, похоже, не работает.

Код:

    import ply.lex as lex
    import ply.yacc as yacc
    tokens = ['HASH','HEADER_FILE','FLOW_OPEN','FLOW_CLOSE','SEMI_COLON',
    'TYPE','SMALL_OPEN','SMALL_CLOSE','IDENTIFIER','COLON',
    'ASSIGNMENT_OP','UNARY_OP','BINARY_OP','LITERAL','LOGICAL_OP']


    reserved = {'include' : 'INCLUDE', 'main': 'MAIN','int':'INT','void':'VOID','for':'FOR','switch':'SWITCH','case':'CASE','default':'DEFAULT','break':'BREAK'}

    tokens += reserved.values()

    t_HASH = r'\#'
    #t_INCLUDE = r'include'
    t_HEADER_FILE = r'<stdio.h>'
    #t_MAIN = r'main' 
    t_FLOW_OPEN = r'{'
    t_FLOW_CLOSE = r'}'
    t_SMALL_OPEN = r'\('
    t_SMALL_CLOSE = r'\)'
    t_SEMI_COLON = r';'
    t_ASSIGNMENT_OP = r'\='
    #t_IDENTIFIER = r'[a-zA-Z][a-zA-Z]*'
    t_UNARY_OP = r'\++|\--'
    #t_BINARY_OP = r'[\+\-\*\/]'
    t_LITERAL = r'[0-9][0-9]*'
    t_LOGICAL_OP = r'\<|\>'
    t_COLON: r':'


    def t_check_reserved(t):
        r'[a-zA-Z][a-zA-Z]*'
        if t.value in reserved:
            t.type = reserved[t.value]
        else:
            t.type = 'IDENTIFIER'
        return t

    def t_error(token):
        print(f'Illegal character: {token.value}')

    def t_whitespace(t):
        r'\s+'
        pass

    def t_COMMENT(t):
        r'(\/\/\/.*)|(\/\/\!.*)|(\/\/.*)|(\/\*[.\n]*.*\*\/)'
        pass

    def t_newline(t):
        r'\n+'
        t.lexer.lineno += len(t.value)

    lexer = lex.lex()
    #Building the parser

    def p_expression_start(p):
        'expression : header body'
        print('Derivation complete!')

    def p_header(p):
        'header : HASH INCLUDE HEADER_FILE'
        print('Deriving rule header')

    def p_body(p):
        'body : main rest'
        print('Deriving rule body')

    def p_main(p):
        'main : type MAIN SMALL_OPEN SMALL_CLOSE'
        print('Deriving rule main')


    def p_type(p):
        '''type : INT
                | VOID
         '''

    def p_rest(p):
        'rest : FLOW_OPEN st FLOW_CLOSE'
        print('Deriving rule rest')

    def p_st(p):
        '''
            st : IDENTIFIER SEMI_COLON st
                | type IDENTIFIER SEMI_COLON st
                | for
                | end
            '''
        print('Deriving rule st')


    def p_for(p):
        '''
        for : FOR SMALL_OPEN declarative SEMI_COLON num_expression SEMI_COLON update_expression SMALL_CLOSE FLOW_OPEN st FLOW_CLOSE
        '''
        print('Deriving rule for')

    def p_declarative(p):
        '''
        declarative : IDENTIFIER ASSIGNMENT_OP IDENTIFIER
                     | IDENTIFIER ASSIGNMENT_OP LITERAL

        '''

    def p_num_expression(p):
        ''' 
        num_expression : LITERAL
                        | IDENTIFIER
                        | conditional_expression  

        '''

    def p_conditional_expression(p):
        '''
        conditional_expression : IDENTIFIER LOGICAL_OP LITERAL
                                | IDENTIFIER LOGICAL_OP IDENTIFIER
                                | empty
        '''

    def p_update_expression(p):
        '''
        update_expression : IDENTIFIER UNARY_OP
                            | empty
        '''



    def p_end(p): #Empty production
        '''end :''' 
        print('Deriving rule end')

    def p_error(p):
        if p == None:
            token = "end of file"
        else:
            token = f"{p.type}({p.value}) on line {p.lineno}"

        print(f"Syntax error: Unexpected {token}")



    parser = yacc.yacc(method='LALR',debug=True)

    with open(r'forparsing.txt','r') as file:
        '''while True:
            try:
                line = next(file)
                print('Parsing')
                parser.parse(line)
            except:
                print('Finished')
                break
        '''
        content = file.read()
        parser.parse(content)

Некоторые из случаев, когда эта программа дает сбой: 1. когда я даю идентификатор или литерал в части num_exp цикла for (то есть в for (init_exp; num_exp;update_exp)), хотя я явно упомянул эти случаи в правиле грамматики:

    def p_num_expression(p):
    ''' 
    num_expression : LITERAL
                    | IDENTIFIER
                    | conditional_expression  

    '''

Более того, программа на C работает, только когда часть conditional_expression имеет форму> 10 (IDENTIFER LOGICAL_OP IDENTIFIER), даже еслиГрамматическое правило для этого нетерминала:

    def p_conditional_expression(p):
    '''
    conditional_expression : IDENTIFIER LOGICAL_OP LITERAL
                            | IDENTIFIER LOGICAL_OP IDENTIFIER
                            | empty
    '''

Таким образом, это только первый из 3 возможных дериваций, которые будут приняты.Использование одной из двух других форм дает мне синтаксическую ошибку.

Редактировать: Это один из входов, для которого я получаю синтаксическую ошибку:

# include <stdio.h>
void main()
{
for(a=15;1;a++)
{

}
}

Это не должно быть ошибкой, так какодин из моих выводов для нетерминального выражения num_expression - это num_expression -> LITERAL.Однако, если я заменю одно условное выражение чем-то вроде> 10, тогда деривация завершится.

Есть ли что-то принципиально неправильное в написанной мной грамматике, из-за которой синтаксический анализатор, по-видимому, не учитываетнекоторые из правил?

...