Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/341.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python-PLY-Yacc-复数的解析除法_Python_Parsing_Yacc_Complex Numbers_Ply - Fatal编程技术网

Python-PLY-Yacc-复数的解析除法

Python-PLY-Yacc-复数的解析除法,python,parsing,yacc,complex-numbers,ply,Python,Parsing,Yacc,Complex Numbers,Ply,我正在用Python实现一个计算器,以便能够对实数和复数进行一些数学运算 我有一个使用PLY的lexer/parser,我正在为复数创建自己的类,自愿忽略Python已经有一个用于复数的内置类型这一事实 解析器工作正常,但以下情况除外: 42i/2i 我的解析器对这种情况的解释如下: 42i/2i=(42*i)/(2*i)=21 正如你在上面看到的,每个复数都像一个块,实部和虚部是不可分割的。但数学真理是不同的。如您所知,此案例应按以下方式处理: 42i/2i=42*i/2*i=-21 我

我正在用Python实现一个计算器,以便能够对实数和复数进行一些数学运算

我有一个使用PLY的lexer/parser,我正在为复数创建自己的类,自愿忽略Python已经有一个用于复数的内置类型这一事实

解析器工作正常,但以下情况除外:

42i/2i
我的解析器对这种情况的解释如下:

42i/2i=(42*i)/(2*i)=21
正如你在上面看到的,每个复数都像一个块,实部和虚部是不可分割的。但数学真理是不同的。如您所知,此案例应按以下方式处理:

42i/2i=42*i/2*i=-21
我应该调整解析器规则以获得正确的结果,但我不知道如何调整。 下面是一个最小的可重复示例:

将ply.lex导入为lex
将ply.yacc导入为yacc
代币=(
“数字”,
"分",,
“想象”,
)
##########################雷克瑟##########################
t_DIVIDE=r'\/'
def t_编号(t):
r'\d+(\.\d+)
t、 value=int(t.value)
返回t
定义t_想象(t):
r'i'
t、 值=复数(0,1)
返回t
def t_错误(t):
打印(“非法字符'%s'%t.value[0])
t、 lexer.skip(1)
##########################分析器#########################
def p_表达式_binop(t):
''表达式:表达式除以表达式''
t[0]=t[1]/t[3]
打印(t[0])
def p_表达式_编号(t):
''表达式:数字
|想象一下“
t[0]=t[1]
def p_表达式(t):
''表达式:数字想象''
t[0]=t[1]*t[2]
def p_错误(t):
打印(“语法错误!”)
######################复杂类######################
类复合体(对象):
定义初始化(自、实、imag=0):
self.real=real
self.imag=imag
定义(自我):
字符串=“”
如果是真的0:
如果self.real%1==0:self.real=int(self.real)
string+=str(self.real)
如果self.imag!=0:
如果self.imag%1==0:self.imag=int(self.imag)
如果是真的0:
字符串+='+'如果self.imag>0,则为'+'其他'-'
其他:
如果self.imag>0,则字符串+='',否则“-”
如果abs(self.imag)!=1:
string+=str(abs(self.imag))+'i'
其他:
字符串+='i'
返回字符串或“0”
定义多个(自身、其他):
返回复数(self.real*other.real-self.imag*other.imag,
self.imag*other.real+self.real*other.imag)
定义(自身、其他):
返回自我(其他)
def _uTrueDiv__;(自身、其他):
如果isinstance(其他,(浮点,int)):
其他=复杂(其他)
s1,s2,o1,o2=自实,自imag,其他.真实,其他.imag
r=浮子(氧气1**2+氧气**2)
返回复合物((s1*o1+s2*o2)/r,(s2*o1-s1*o2)/r)
定义(自身、其他):
如果isinstance(其他,(浮点,int)):
其他=复杂(其他)
返回其他
##########################主要##########################
lexer=lex.lex()
尽管如此:
尝试:
s=原始输入(“>”)
除:
s=输入(“>”)
如果是:
parser=yacc.yacc()
parser.parse(s)

有什么帮助吗?非常感谢

您的程序缺少一件事:

precedence = (
    ('left', 'DIVIDE'),
)
否则,Ply在生成解析器时会生成一个shift-reduce冲突,因为生成

expression : expression DIVIDE expression
expression : expression IMAGINE
我之所以提到这一点,是因为当前的问题是运算符优先级问题,尽管所讨论的运算符是不可见的:生产中包含的隐式乘法运算符:

expression : NUMBER IMAGINE
第二个产品不会导致任何解析冲突,即使没有优先级声明,但这是因为它不够通用,无法实际解析有用的表达式。考虑一下,例如,你的例子

42i/4i
正如您所说,您的解析器将其解释为

[expression: [expression: 42 i]
             /
             [expression: 4 i] ]
但你希望它被解释为:

[expression: [expression: [expression: 42 i]
                          /
                          [expression: 4]
              i]
]
但是很明显,最外层的
表达式
不能从语法中生成,因为语法要求隐式乘法的左边运算符是
数字
,在这个解析中,它显然是一个
表达式

在我们添加产品之前

expression : expression DIVIDE expression
expression : expression IMAGINE
我们可能应该尝试想象所有可能的用例。其中一个应该会立即浮现在脑海中:
4i2
(省去选择哪个操作符表示求幂的细节)

不正确的“融合数字想象”语法将其视为
4i
(即-16)的平方,但普遍接受的解析是
i
(即-4)平方的四倍。这将对应于解析

[expression: [expression: 4]
             [expression: [expression: i]
                          POWER
                          [expression: 2]]]
其中隐式乘法的右参数不是一个假想的,而是一个表达式

所以你的第一个任务是决定隐式乘法在你的语言中的通用性。下列各项都有效吗?(有些要求lexer丢弃空白)

你可能会对最后的几条有所怀疑,但我大胆猜测,其中大部分不会引起任何惊讶。如果需要的话,我们可以在后面研究如何拒绝两个连续数的情况,但似乎最合理的隐式乘法规则至少与最一般的规则相似:

expression : expression expression
而且,它与除法或显式乘法具有完全相同的优先级和结合性

但这给我们留下了一个问题:当没有运算符时,如何将运算符放在优先级表中?简而言之,你不能。有一些技巧或多或少是有效的,但最简单和最可读的替代方法是编写语法,以便优先顺序是明确的

我不去
import ply.lex as lex
import ply.yacc as yacc

### Lexer

# This lexer uses literal character tokens wherever possible. They're
# easier, faster, and more readable.
# (https://www.dabeaz.com/ply/ply.html#ply_nn11)

literals = '()+-*/^i'
t_ignore = ' \t'
tokens = ( 'NUMBER', )

def t_NUMBER(t):
    "(?:\d+(?:\.\d*)?|\.\d+)(?:[Ee][+-]?\d+)?"
    t.value = float(t.value)
    return t

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

### Parser

# Use this function for any unit production which just passes
# its value through.
def p_unit(p): 
    """ expression : additive
        additive : multiplicative
        multiplicative : exponential
        exponential : value
        value : NUMBER
    """
    p[0] = p[1]

def p_plus(p):
    """ additive : additive '+' multiplicative """
    p[0] = p[1] + p[3]

def p_minus(p):
    """ additive : additive '-' multiplicative """
    p[0] = p[1] - p[3]

# Compare this production with the next one.
def p_implicit_times(p):
    """ multiplicative : multiplicative exponential """
    p[0] = p[1] * p[2]


def p_times(p):
    """ multiplicative : multiplicative '*' exponential """
    p[0] = p[1] * p[3]

# TODO: catch errors
def p_divide(p):
    """ multiplicative : multiplicative '/' exponential """
    p[0] = p[1] / p[3]

# This one is right-associative.
# TODO: catch errors
def p_power(p):
    """ exponential : value '^' exponential """
    p[0] = p[1] ** p[3]

def p_i(p):
    """ value : 'i' """
    p[0] = 1J   # Python's way of writing 0+1i

def p_paren(p):
    """ value : '(' expression ')' """
    p[0] = p[2]

def p_error(t):
    print("Syntax error at " + str(t))

### Very simple driver

import sys
lexer = lex.lex()
parser = yacc.yacc()
while True:
    try:
        print(parser.parse(input('> ')))
    except EOFError:
        break
    except:
        print(sys.exc_info()[1])
Rule 1     expression -> additive
Rule 2     additive -> multiplicative
Rule 3     multiplicative -> exponential
Rule 4     exponential -> value
Rule 5     value -> NUMBER
Rule 6     additive -> additive + multiplicative
Rule 7     additive -> additive - multiplicative
Rule 8     multiplicative -> multiplicative exponential
Rule 9     multiplicative -> multiplicative * exponential
Rule 10    multiplicative -> multiplicative / exponential
Rule 11    exponential -> value ^ exponential
Rule 12    value -> i
Rule 13    value -> ( expression )
expression : expression expression
Rule 1     expression -> additive
Rule 2     additive -> multiplicative
Rule 3     multiplicative -> unary
Rule 4     unary -> exponential
Rule 5     exponential -> value
Rule 6     value -> NUMBER
Rule 7     additive -> additive + multiplicative
Rule 8     additive -> additive - multiplicative
Rule 9     multiplicative -> multiplicative exponential
Rule 10    multiplicative -> multiplicative * unary
Rule 11    multiplicative -> multiplicative / unary
Rule 12    unary -> - unary
Rule 13    exponential -> value ^ unary
Rule 14    value -> i
Rule 15    value -> ( expression )