I am coding a parser to c-minus language. Lexer is ready and working properly, so I began develop parser but I can't pass from the first part: i am receiving an error that don't let me move forward, because I can se whats is right and what is wrong, I only see this error reproduced below. I try to change parser builder but still don't work.
This code below is Lexer that is working. It builds a lexer that identifies all symbols of grammar.
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'
This code below is Parser that is still in development. But I can't test none of the functions I am creating because the error that is ocurring.
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))
Main:
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')
Below is the complete error:
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?
CodePudding user response:
If you put the parser definitions into a class or you try to build the parser from a different module, you need to use the module=
parameter to tell yacc
where the rules are. Otherwise, it can't find them and you get an error saying that no rules were found. So instead of parser = yacc.yacc()
, you need:
parser = yacc.yacc(module=Parser)
Note that all of the parser rules need to be in the same namespace; that includes the definition of tokens
. So you'll need to put that inside the class:
class Parser():
tokens = lexer.tokens
# ...
Also, Ply insists that productions be written with whitespace on both sides of the colon, so you'll have to fix that. And there are a number of other errors; notably, parsers are not called the same way as lexers; they don't return a generator of tokens. Generally, you only call the parser once to parse the entire input. The details are in the Ply manual.