使用Python的PLY库更改lexing规则

时间:2013-09-15 15:47:28

标签: python lexical-analysis ply

在我的编译器类中,我们的讲师告诉我们,我们将实现的语言的语法将需要在解析器中进行预测。使用像flex这样的工具,可以使用foo/x轻松完成。

我目前正在尝试使用PLY库在Python中执行示例程序,以查看Python是否适合该项目。我正在尝试实现FORTRAN的do循环的简单版本:

-- Spaces are ignored in FORTRAN
DO 5 I=1,10   -- Loop
DO 5 I=1.10   -- Assignment (DO5I = 1.10)

目前,我的想法是匹配DO关键字,预先查看输入的其余部分是否与循环匹配。如果是,请返回DO令牌。否则,我想“回滚”输入并进入标识符规则。类似的东西:

def t_do(t):
    'do'
    if re.match(do_loop_regex, t.lexer.lexdata[t.lexer.lexpos:]):
        return t
    else:
        t.rewind() # this is what I need to figure out
        return t_identifier(t)

def t_identifier(t):
    '[A-Z_][A-Z0-9_]*'
    return t

1 个答案:

答案 0 :(得分:1)

可以使用Ply,但需要一些数据按摩和令牌构建。

import re
from ply import lex

tokens = ('LOOP','ASSIGNMENT')
literals = '=,'

re_float = r'(\d+\.\d+)'
re_int = r'(\d+)'
re_ident = r'([A-Za-z]\w*)'
re_expr = '(%s)' % '|'.join([re_float, re_int, re_ident])

re_loop = 'DO%s%s=%s,%s' % (re_int, re_ident, re_expr, re_expr)
@lex.TOKEN(re_loop)
def t_LOOP(t):
    return t

re_assignment = '%s=%s' % (re_ident, re_expr)
@lex.TOKEN(re_assignment)
def t_ASSIGNMENT(t):
    return t

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

def t_error(t):
    print "syntax error at %s, line# %d" % (t.value, t.lineno)

DATA = """-- Spaces are ignored in FORTRAN
DO 5 I=1,10   -- Loop
DO 5 I=1.10   -- Assignment (DO5I = 1.10)"""

def preprocess(data):
    re_spaces=re.compile('\s*')
    re_comment=re.compile('--.*$')
    lines = []
    for line in data.split('\n'):       # split into lines
        line = re_spaces.sub('', line)
        line = re_comment.sub('', line)
        if not line: continue           # skip blank lines
        line = line.upper()
        lines.append(line)
    return '\n'.join(lines)+'\n'

print re_assignment
lexer = lex.lex()
lexer.input(preprocess(DATA))
while True:
    tok = lexer.token()
    if not tok: break
    print tok

首先,您必须手动将注释,空格和强制删除为大写。然后你构建一个解析器,它基本上实现你的语法内联。我认为它最终会变得难以管理。如果是我,我认为实现我自己的词法分析器会更容易,它只是逐行正则表达式匹配。所有Ply的lexer真正做的就是用你所有的小正则表达式构建一个巨大的正则表达式,然后逐步匹配标记。