Я использую пакет PLY python для создания внешнего компилятора для подмножества C, но я все еще пытаюсь понять, как работает анализатор снизу вверх (в частности, LALR). Я написал простую программу с заданной грамматикой, чтобы увидеть, как все работает:
expression -> vowel_list consonant_list
vowel_list -> VOWEL vowel_list
| VOWEL
consonant_list : CONSONANT consonant_list
| CONSONANT
И использовал входную строку: 'EUAIOTNC'
В качестве действия для различных правил грамматики я использую список, в который я добавляю все токены, которые видит анализатор. По сути, токен добавляется в список, когда происходит сокращение. В конце синтаксического анализа, когда получено выражение начального символа, список выглядит так: ['O', 'I', 'A', 'U', 'E', 'C', 'N', 'T'] .
import ply.lex as lex
import ply.yacc as yacc
tokens = ['VOWEL','CONSONANT']
t_VOWEL = r'[AEIOUaeiou]'
t_CONSONANT = r'[A-Za-z]'
def t_error(token):
print(f'Illegal character: {token.value} on line number {t.lineno}')
token.lexer.skip(1)
def t_whitespace(t):
r'\s+'
pass
lexer = lex.lex()
tokens_generated = []
def p_expression(p):
'''
expression : vowel_list consonant_list
'''
print(p.stack)
print('Derivation complete!')
print(f'The tokens generated are: {tokens_generated}')
def p_vowel_list(p):
'''
vowel_list : VOWEL vowel_list
| VOWEL
'''
print(f'Derived the vowel {p[1]} !')
tokens_generated.append(p[1])
def p_consonant_list(p):
'''
consonant_list : CONSONANT consonant_list
| CONSONANT
'''
print(f'Derived the consonant {p[1]}!')
tokens_generated.append(p[1])
def p_error(p):
if p == None:
token = "end of file"
else:
token = f"{p.type}({p.value}) on line {p.lineno}"
input_string = 'EUAIOTNC'
parser = yacc.yacc(method='LALR',debug=True)
parser.parse(input_string)
Вывод, который я получаю:
Derived the vowel O !
Derived the vowel I !
Derived the vowel A !
Derived the vowel U !
Derived the vowel E !
Derived the consonant C!
Derived the consonant N!
Derived the consonant T!
[$end]
Derivation complete!
The tokens generated are: ['O', 'I', 'A', 'U', 'E', 'C', 'N', 'T']
Я не могу понять, как это происходит. Я ожидал, что список будет содержать токены в том же порядке, что и в строке. Может кто-нибудь объяснить, почему я получаю то, что получаю? Как синтаксический анализатор LALR анализирует мой ввод?