Маркировка письма в качестве оператора - PullRequest
0 голосов
/ 22 мая 2019

Мне нужно создать язык, в котором есть переменные, но ему также нужна буква «d», чтобы быть операндом с числом справа и, возможно, числом слева. Я думал, что проверка лексера на наличие буквы сначала даст ему преимущество, но этого не происходит, и я не знаю почему.

from ply import lex, yacc

tokens=['INT', 'D', 'PLUS', 'MINUS', 'LPAR', 'RPAR', 'BIGGEST', 'SMALLEST', 'EQ', 'NAME']

t_PLUS     = r'\+'
t_MINUS    = r'\-'
t_LPAR     = r'\('
t_RPAR     = r'\)'
t_BIGGEST  = r'\!'
t_SMALLEST = r'\#'
t_D        = r'[dD]'
t_EQ       = r'\='
t_NAME     = r'[a-zA-Z_][a-zA-Z0-9_]*'

def t_INT(t):
    r'[0-9]\d*'
    t.value = int(t.value)
    return t


def t_newline(t):
    r'\n+'
    t.lexer.lineno += 1


t_ignore = ' \t'

def t_error(t):
    print("Not recognized by the lexer:", t.value)
    t.lexer.skip(1)

lexer = lex.lex()

while True:
    try: s = input(">> ")
    except EOFError: break
    lexer.input(s)
    while True:
        t = lexer.token()
        if not t: break
        print(t)

Если я напишу: 3d4 выводит:

LexToken(INT,3,1,0)
LexToken(NAME,'d4',1,1)

и я не знаю, как обойти это.

1 Ответ

1 голос
/ 22 мая 2019

Ply не определяет приоритеты переменных токена в порядке их появления;скорее он упорядочивает их в порядке убывания по длине (самый длинный сначала).Таким образом, ваш шаблон t_NAME появится раньше t_D.Это объясняется в руководстве Ply вместе с конкретным примером того, как обрабатывать зарезервированные слова (которые могут не применяться в вашем случае).

Если я правильно понимаю, буква d не может быть идентификатором, а также d, за которым следует число.Мне не совсем ясно, ожидаете ли вы, что d2e будет правдоподобным идентификатором, но для простоты я предполагаю, что ответом будет «Нет», и в этом случае вы можете легко ограничить регулярное выражение t_NAME, потребовавинициал d, за которым следует еще одна буква:

t_NAME = '([a-ce-zA-CE-Z_]|[dD][a-zA-Z_])[a-zA-Z0-9_]*'

Если вы хотите, чтобы d2e было именем, то вы можете использовать:

t_NAME = '([a-ce-zA-CE-Z_]|[dD][0-9]*[a-zA-Z_])[a-zA-Z0-9_]*'
...