PLY ya cc синтаксический анализатор: как я могу обрабатывать неизвестные значения, такие как мнимые числа? - PullRequest
0 голосов
/ 23 февраля 2020

Я использую PLY: lex и ya cc для создания вида команды 'b c': с возможностью разрешения, но также и для назначения переменных.

Так что я могу разрешить вещи вот так: 1 + 3.12 - 4 = ? или 5 * 3 = ? или (1 + 3) * 7 /2 = ?

А также такие вещи, зная, что 'ab c' = 10: (abc + 3 * abc) * 2 = ?

Но я действительно не знаю, как мне обращаться с неизвестными значениями или комплексными числами, такими как мнимые числа.

Как я могу справиться с этим: 2 * 2 * i + 3 - 1, который должен быть равен 4i + 2

Я не могу придумать правило разбора для обработки воображаемого числа. Любая помощь?

Мой код:

1. основной код:

from global_variables import tokens
from lexer import lexer
from parser import parser


while True:
    s = input('> ')
    if s:

        # lexer.input(s)
        # while True:
        #     tok = lexer.token()
        #     if not tok:
        #         break
        #     print(tok)

        parser.parse(s)

2. лексер:

from global_variables import tokens
import ply.lex as lex

t_PLUS      = r'\+'
t_MINUS     = r'\-'
t_TIMES     = r'\*'
t_DIVIDE    = r'\/'
t_MODULO    = r'\%'
t_EQUALS    = r'\='
t_LPAREN    = r'\('
t_RPAREN    = r'\)'
t_POWER     = r'\^'
t_QUESTION  = r'\?'
t_NAME      = r'[a-zA-Z]{2,}|[a-hj-zA-HJ-Z]'    # all words (only letters) except the word 'i' alone
t_IMAGINE   = r'i'                              # the word 'i' alone
t_COMMAND   = r'![\x00-\x7F]*'                  # all unicode characters after '!'

def t_NUMBER(t):
    r'\d+(\.\d+)?'
    try:
        t.value = int(t.value)
    except:
        t.value = float(t.value)
    return t

t_ignore = " \t"

def t_error(t):
    print("Illegal character '%s'" % t.value[0])
    t.lexer.skip(1)

lexer = lex.lex()

3. парсер:

from global_variables import tokens
from global_variables import variables
from global_variables import prRed
from global_variables import prGreen
from global_variables import prLightPurple
import ply.yacc as yacc


precedence = (
    ('left','PLUS','MINUS'),
    ('left','TIMES','DIVIDE'),
    ('right','UMINUS'),
    )

def p_statement_assign(t):
    'statement : NAME EQUALS expression'
    variables[t[1].lower()] = t[3]
    print(t[3])

def p_statement_expr(t):
    '''statement : expression
                | expression EQUALS QUESTION'''
    print(t[1])

def p_expression_binop(t):
    '''expression : expression PLUS expression
                 | expression MINUS expression
                 | expression TIMES expression
                 | expression DIVIDE expression
                 | expression POWER expression
                 | expression MODULO expression'''
    if t[2] == '+': t[0] = t[1] + t[3]
    elif t[2] == '-': t[0] = t[1] - t[3]
    elif t[2] == '*': t[0] = t[1] * t[3]
    elif t[2] == '%': t[0] = t[1] % t[3]
    elif t[2] == '^': t[0] = t[1] ** t[3]
    elif t[2] == '/': t[0] = float(t[1]) / float(t[3])

    if t[0] % 1 == 0:
        t[0] = int(t[0])
    else:
        t[0] = float(t[0])


def p_expression_uminus(t):
    'expression : MINUS expression %prec UMINUS'
    t[0] = -t[2]

def p_expression_group(t):
    'expression : LPAREN expression RPAREN'
    t[0] = t[2]

def p_expression_number(t):
    '''expression : NUMBER
                 | IMAGINE'''
    t[0] = t[1]

def p_expression_name(t):
    '''expression : NAME
                 | NAME EQUALS QUESTION'''
    try:
        t[0] = variables[t[1].lower()]
    except LookupError:
        prRed("Undefined name '%s'" % t[1])
        t[0] = 0

def p_execute_command(t):
    'statement : COMMAND'
    letter = t[1].split('!')[1]
    if letter == 'h':
        prGreen("Help:")
        print("    - !p = print all variables")
        print("    - !q = quit the computor")
    elif letter == 'p':
        if variables:
            prGreen("Variables:")
            for key,value in variables.items():
                print("     {} = {}".format(key, value))
        else:
            prRed("Variables:")
            print("     There are no variables")
    elif letter == 'q':
        prGreen("Bye bye!")
        exit()
    else:
        print("Type '!h' for help.")


def p_error(t):
    if t:
        print("Syntax error at '%s'" % t.value)  
    else:
        print("Syntax error!")


parser = yacc.yacc()

4. некоторые глобальные переменные:

tokens = (
    'NAME',
    'NUMBER',
    'PLUS',
    'MINUS',
    'TIMES',
    'DIVIDE',
    'MODULO',
    'EQUALS',
    'LPAREN',
    'RPAREN',
    'POWER',
    'QUESTION',
    'IMAGINE',
    'COMMAND',
)

variables = {}

def prRed(skk): print("\033[91m{}\033[00m" .format(skk))
def prGreen(skk): print("\033[92m{}\033[00m" .format(skk))
def prLightPurple(skk): print("\033[94m{}\033[00m" .format(skk))

1 Ответ

0 голосов
/ 24 февраля 2020

i - это просто зарезервированное имя, поэтому вы можете узнать его как таковое в лексере (так же, как и любое другое ключевое слово). Если вы действительно хотите, чтобы 2i был действительным, вам понадобится немного больше работы в лексере, но должно быть понятно, что нужно. (В качестве альтернативы вы можете поместить это в анализатор так, чтобы 2 i также было допустимым, но я должен сказать, что это выглядит странно для меня.)

Так что ваша проблема на самом деле не является проблемой синтаксического анализа , Все, что вам нужно, это комплексный тип данных, который Python удобно уже имеет . (Также см. Это краткое объяснение .)

Ply не накладывает никаких ограничений на значения semanti c. Если вы хотите использовать комплексные числа, просто используйте их. (Но обратите внимание, что Python использует j вместо i для jmagjnary чисел. Это не значит, что вы должны использовать их тоже, но если вы хотите использовать i, вам придется делать явные преобразования числа в строку.)

...