我正在将python转换为c ++转换器。现在,我正在完成语法语法,并且if-else块存在一些问题。事实是我不知道要用列表来检测块的结尾。现在我要测试这个文件了:
print(33)
if a<3:
print(test);
b=5
它给我以下结果:
Program
| print
| | '33'
| if
| | < (2)
| | | 'a'
| | | '3'
| | Program
| | | print
| | | | 'test'
| =
| | 'b'
| | '5'
这是正确的,因为b = 5与我的水平处于同一水平。这是我的lex令牌:
reserved_words = (
'if',
'print',
'range',
'for',
'in',
'while'
)
tokens = (
'COMPARATOR',
'IDENTIFIER',
'ILLEGAL',
'FLOAT',
'INT',
'EQU',
'ENTER',
'POINTS',
'TAB',
'END'
) + tuple(map(lambda s:s.upper(),reserved_words))
literals = ';():\s'
def t_ENTER(t):
r'\n'
return t
def t_ADD_OP(t):
r'\+|-'
return t
def t_POINTS(t):
r':'
return t
def t_EQU(t):
r'\='
return t
def t_MUL_OP(t):
r'\*|/'
return t
def t_COMPARATOR(t):
r'[<>]'
return t
def t_INT(t):
#r'\d+(?!\.)(?![a-zA-Z])'
r'\b(?<!\.)\d+(?!\.)\b'
try:
t.value = t.value
except ValueError:
print ("Line %d: Problem while parsing %s!" % (t.lineno,t.value))
t.value = 0
return t
def t_ILLEGAL(t):
r'\d+[a-zA-z]+'
try:
t.value = t.value
except ValueError:
print ("Line %d: Problem while parsing %s!" % (t.lineno,t.value))
t.value = 0
return t
def t_FLOAT(t):
r'\d+\.{1}\d+'
try:
t.value = float(t.value)
except ValueError:
print ("Line %d: Problem while parsing %s!" % (t.lineno,t.value))
t.value = 0.0
return t
def t_IDENTIFIER(t):
r'[A-Za-z_]\w*'
if t.value in reserved_words:
t.type = t.value.upper()
return t
def t_TAB(t):
r'[ \t]{4}'
return t
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value)
def t_error(t):
print ("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
t_ignore = ' '
lex.lex()
还有我的规则:
vars = {}
def p_programme_statement(p):
''' programme : statement '''
p[0] = AST.ProgramNode(p[1])
def p_programme_recursive(p):
''' programme : statement ENTER programme '''
p[0] = AST.ProgramNode([p[1]]+p[3].children)
def p_statement(p):
''' statement : assignation
| structure '''
p[0] = p[1]
def p_expression_num_or_var(p):
'''expression : INT
| FLOAT
| IDENTIFIER
'''
p[0] = AST.TokenNode(p[1])
def p_statement_print(p):
''' statement : PRINT '(' expression ')' '''
p[0] = AST.PrintNode(p[3])
def p_expression_comp(p):
''' expression : expression COMPARATOR expression'''
p[0] = AST.OpNode(p[2],[p[1],p[3]])
def p_structure_if(p):
'''structure : IF expression POINTS ENTER programme ';' '''
p[0] = AST.IfNode([p[2],p[5]])
def p_structure_while(p):
''' structure : WHILE expression POINTS ENTER programme '''
p[0] = AST.WhileNode([p[2],p[5]])
def p_expression_paren(p):
'''expression : '(' expression ')' '''
p[0] = p[2]
def p_assign_block(p):
''' assignation : TAB IDENTIFIER EQU expression'''
p[0] = AST.AssignNode([AST.TokenNode(p[2]),p[4]])
def p_assign(p):
''' assignation : IDENTIFIER EQU expression '''
p[0] = AST.AssignNode([AST.TokenNode(p[1]),p[3]])
def p_error(p):
print ("Syntax error in line %d" % p.lineno)
yacc.errok()
事情是:我的p_Structure_if是错误的,因为现在我说代码块的末尾是';'出现。如何通过检查列表来检测块的结尾(如果下一行不在另一块的同一列表级别,则它不是同一块,然后不使用';'字符?
预先道歉,这不是一个完整的答案,但是它远远超出评论范围,我希望它对您有用。
Python官方文档包含BNF grammar for the full language。
棘手的部分是,您需要生成适当数量的“ dedent”标记以与制表符一起使用(正式语法称为INDENT
)。同样,我们只在一行的开头真正关心空白。
t_TAB
正则表达式必须类似于^[ \t]*
(因为您需要能够检查没有任何前导空格的行,以便您知道代码何时返回顶层) )。但是,(当然是设计使然)匹配一个空字符串,因此每行只需要测试一次-我不确定ply
是否适合该任务,或者至少我不知道该如何使用使这项工作。
[无论如何,您然后需要检查t_TAB()
中的空格字符串,以找出对应的缩进级别(如果要匹配Python的正式行为,请使用一堆以前看到的缩进字符串;如果要更严格一些,那么我想您可以对制表符/空格的数量进行数学运算),然后发出单个INDENT或零个或多个DEDENT(这是我不确定的另一件事,ply是否支持从单个单个键生成多个标记)令牌正则表达式-您可能需要使用t.lexer
属性或其他属性进行修改。