ply.yacc error: 'ERROR: no rules of the form p_rulename are defined'

ply.yacc error: 'ERROR: no rules of the form p_rulename are defined'

我正在为 c-minus 语言编写解析器。 Lexer 准备就绪并正常工作,所以我开始开发解析​​器,但我无法从第一部分通过:我收到一个错误,不允许我继续前进,因为我可以看出什么是对的,什么是错的,我只看到下面重现了这个错误。我尝试更改解析器生成器,但仍然无法正常工作。

下面的这段代码是正在运行的词法分析器。它构建了一个识别所有语法符号的词法分析器。

reserved = {
    'else' : 'ELSE',
    'if' : 'IF',
    'int' : 'INT',
    'return' : 'RETURN',
    'void' : 'VOID',
    'while' : 'WHILE'
}

tokens = [
    'ID',
    'NUM',
    'PLUS',
    'MINUS',
    'MULT',
    'DIV',
    'LESS',
    'LESSOREQUAL',
    'GREAT',
    'GREATOREQUAL',
    'DOUBLEEQUAL',
    'NOTEQUAL',
    'EQUAL',
    'SEMICOLON',
    'COLON',
    'LPAREN',
    'RPAREN',
    'LBRACKET',
    'RBRACKET',
    'LKEY',
    'RKEY',
    'COMENT'
] + list(reserved.values())

def t_COMENT(t):
    r'/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/'
    return t

def t_ID(t):
    r'[a-zA-Z]+'
    return t

def t_NUM(t):
    r'[0-9]+'
    return t

def t_PLUS(t):
    r'\+'
    return t

def t_MINUS(t):
    r'\-'
    return t

def t_MULT(t):
    r'\*'
    return t

def t_DIV(t):
    r'\/'
    return t

def t_LESS(t):
    r'\<'
    return t

def t_LESSOREQUAL(t):
    r'\<\='
    return t

def t_GREAT(t):
    r'\>'
    return t

def t_GREATOREQUAL(t):
    r'\>\='
    return t

def t_DOUBLEEQUAL(t):
    r'\=\='
    return t

def t_NOTEQUAL(t):
    r'\!\='
    return t

def t_EQUAL(t):
    r'\='
    return t

def t_SEMICOLON(t):
    r'\;'
    return t

def t_COLON(t):
    r'\,'
    return t

def t_LPAREN(t):
    r'\('
    return t

def t_RPAREN(t):
    r'\)'
    return t

def t_LBRACKET(t):
    r'\['
    return t

def t_RBRACKET(t):
    r'\]'
    return t

def t_LKEY(t):
    r'\{'
    return t

def t_RKEY(t):
    r'\}'
    return t

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

def t_error(t):
    print("ERROR: Illegal character '{0}' at line {1}".format(t.value[0], t.lineno))
    t.lexer.skip(1)

t_ignore  = ' \t'

下面这段代码是仍在开发中的解析器。但是我无法测试 none 我正在创建的函数,因为发生了错误。

import ply.yacc as yacc
import lexer

tokens = lexer.tokens

class Parser():

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

    def p_declaration_list(p):
        '''declaration_list: declaration_list declaration
                           | declaration'''
        p[0] = (0, (p[1], 0))

主要:

import ply.yacc as yacc
import ply.lex as lex
from tabulate import tabulate
import sys
from lexer import *
from parser import Parser

lexer = lex.lex()

with open(sys.argv[1], 'r') as f:
    lexer.input(f.read())
    tok_array = [[tok.type, tok.value, tok.lexpos, tok.lineno] for tok in lexer]
    print(tabulate(tok_array, headers=['Tipo','Valor','Posição','Linha']),'\n')

print('passou aqui 1')
parser = yacc.yacc()

with open(sys.argv[1], 'r') as f:
    parser.input(f.read())
    tok_array = [[tok.type, tok.value, tok.lexpos, tok.lineno] for tok in parser]
    print(tabulate(tok_array, headers=['Tipo','Valor','Posição','Linha']),'\n')

下面是完整的错误:

ERROR: no rules of the form p_rulename are defined
Traceback (most recent call last):
  File "main.py", line 16, in <module>
    parser = yacc.yacc()
  File "/home/tlunafar/.local/lib/python3.8/site-packages/ply/yacc.py", line 3323, in yacc
    raise YaccError('Unable to build parser')
ply.yacc.YaccError: Unable to build parser
```

Here is the program in c-minus that i am testing:
```
int gcd(int u) {
    if (v == 0) return u;
    &
    else return gcd(v, u-u/v*v);
    /* comment */
}
```

Where exactly is this error? Can anybody show me?

如果将解析器定义放入 class 或尝试从不同的模块构建解析器,则需要使用 module= 参数来告诉 yacc规则是。否则,它找不到它们,您会收到一条错误消息,指出没有找到规则。因此,您需要:

而不是 parser = yacc.yacc()
parser = yacc.yacc(module=Parser)

请注意,所有解析器规则都需要在同一个命名空间中;其中包括 tokens 的定义。所以你需要把它放在 class:

class Parser():
    tokens = lexer.tokens
    # ...

此外,Ply 坚持要求作品的冒号两边都有空格,因此您必须解决这个问题。还有许多其他错误;值得注意的是,解析器的调用方式与词法分析器不同;他们不是 return 令牌生成器。通常,您只调用一次解析器来解析整个输入。详情在 Ply 手册中。