首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python PLY:获取每一行输入的语法错误

Python PLY:获取每一行输入的语法错误
EN

Stack Overflow用户
提问于 2019-03-01 03:19:34
回答 1查看 1.6K关注 0票数 0

致力于为C的for循环结构编写编译器,然而,我仍然停留在解析C程序的开始部分的初步任务上,即要包含的头文件和main函数。

下面是我的代码:

代码语言:javascript
复制
import ply.lex as lex
import ply.yacc as yacc
tokens = ('HASH','INCLUDE','HEADER_FILE','MAIN','FLOW_OPEN','FLOW_CLOSE','SEMI_COLON','TYPE','SMALL_OPEN','SMALL_CLOSE','OTHERS')

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_OTHERS = r'[a-zA-Z][a-zA-Z]*'
t_TYPE = r'int|void'

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

def t_whitespace(t):
    r'\s+'
    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'

def p_header(p):
    'header : HASH INCLUDE HEADER_FILE'

def p_body(p):
    'body : main rest'

def p_main(p):
    'main : TYPE MAIN SMALL_OPEN SMALL_CLOSE'

def p_rest(p):
    'rest : FLOW_OPEN st FLOW_CLOSE'

def p_st(p):
    ''''
        st : OTHERS st
            | end
        '''
def p_end(p): #Empty production
    'end : SEMI_COLON' 

def p_error(p):
    print("Syntax error in input!")

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

我给出的输入是:

代码语言:javascript
复制
# include <stdio.h>
void main()
{
 abc;
 }

但是在运行程序时,我在每一行上都得到了一个语法错误。这里可能出了什么问题。据我所知,解析器不能从给定的输入中导出开始符号,但我不知道如何解决这个问题。一般来说,我如何调试PLY的语法错误问题?

EN

回答 1

Stack Overflow用户

发布于 2019-03-01 04:11:43

您的输入行本身在语法上都不是有效的。它们只有在作为一个整体被解析时才会形成一个语法上有效的程序。因此,您需要使用包含整个程序的字符串调用parse一次,而不是每行调用一次。

只需在文件处理代码中调用file.read(),而不使用while循环,就可以做到这一点。

修复后遇到的语法错误是由于PLY中处理重叠词法规则的方式造成的。在sane lexer生成器中,生成最长匹配的规则获胜,如果两者都生成相同的匹配,则在代码中最先出现的规则获胜。然而,在PLY中,具有最长正则表达式的那个将获胜。由于这种行为,您不能使用PLY使用单独的规则来匹配标识符和关键字。在这种情况下,即使t_INCLUDE也匹配,也会使用t_OTHERS规则。

相反,the PLY documentation建议使用以下匹配标识符和关键字的方法:

要处理保留字,您应该编写单个规则来匹配标识符,并在如下所示的函数中执行特殊的名称查找:

保留={ 'if‘:'IF','then’:'THEN','else‘:'ELSE','while’:'WHILE',... } tokens = 'LPAREN','RPAREN',...,'ID‘+ list(reserved.values()) def t_ID(t):r'a-zA-Z_*’t.type = reserved.get(t.value,‘'ID') #检查保留字是否返回t

这种方法极大地减少了正则表达式规则的数量,并且可能会使事情变得更快一些。

注意:您应该避免为保留字编写单独的规则。例如,如果您像这样编写规则,

t_FOR =r‘对于’t_PRINT =r‘打印’

这些规则将为包括这些单词作为前缀的标识符触发,例如“忘记”或“打印”。这可能不是您想要的。

同样,需要指出的是,使用最大munch规则的词法分析器生成器中不存在上述两个问题。

一般来说,我如何调试PLY的语法错误问题?

第一步是更改p_error以打印出一些有用的信息(比如哪一行上的哪种类型的标记导致了语法错误),如下所示:

代码语言:javascript
复制
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}")
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54932793

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档