0

Python で英語の単語と数字を認識する計算機を実行するための演習の助けを求めたいのですが、現在は PLY (Python Lex-Yacc) を使用しています。

数字と演算子は、「plus」=「+」、「two」=2、「112」=112 など、英単語を使用して文字列として記述された 2 つの形式で指定できます。

例としては、次のエントリがあります。

「25 割る 5」または「25 / 5」または「25 割る 5」

結果は同じで、数字の 5 (文字列ではありません) になります。

" -3 かける 4" は -12 になります

0 で割ると「エラー」になります。「34 を 0 で割ると」エラーになります。

これは、いくつかの基本的な演算子「-」、「+」、「x」、および「/」(マイナス、プラス、時間、および除算)に対して、数学記号を入力するか、テキストを入力するか、混合した場合に機能するはずです。

ここに私のコードのいくつかの部分があります:

# ------- Calculator tokenizing rules

tokens = (
    'NAME','NUMBER', 'times', 'divided_by', 'plus', 'minus'
)

literals = ['=','+','-','*','/', '(',')']

t_ignore = " \t"

t_plus    = r'\+'
t_minus   = r'-'
t_times   = r'\*'
t_divided_by  = r'/'
t_NAME    = r'[a-zA-Z_][a-zA-Z0-9_]*'

  precedence = (
    ('left','+','-'),
    ('left','plus','minus'),
    ('left','times','divided_by'),
    ('left','*','/'),
    ('right','UMINUS'),
)

#代入定義をここで変更しました。

def p_statement_expr(p):
    'statement : expression'
    p[0] = p[1]

def p_expression_binop(p):
    '''expression : expression '+' expression
                  | expression 'plus' expression
                  | expression '-' expression
                  | expression 'minus' expression
                  | expression '*' expression
                  | expression 'times' expression
                  | expression 'divided_by' expression
                  | expression '/' expression'''
    if p[2] ==   '+'  : p[0] = p[1] + p[3]
    elif p[2] == '-': p[0] = p[1] - p[3]
    elif p[2] == '*': p[0] = p[1] * p[3]
    elif p[2] == '/': p[0] = p[1] / p[3]

トークンの定義が間違っていませんか? 数字が英語の文字または数字で紹介できることをどのように判断できますか?

(p[2] == '+' : p[0] = p[1] + p[3])は 1 文字である必要があります。このフォームに書くことが有効でないのはなぜp[2] == 'plus' : p[0] = p[1] + p[3]ですか?


sfk によって提案されたコードを追加しましたが、英単語でテキストとして入力された数字と演算子を認識するのにまだ問題があります。

Generating LALR tables
WARNING: 12 shift/reduce conflicts
 Enter your input: calc > one + two
Undefined name 'one'
Undefined name 'two'
P1 is :  0
 Enter your input: calc > 1+2
P1 is :  3
3
 Enter your input: calc > 1 plus 2
Syntax error at 'plus'
P1 is :  2
2

私が間違っていることについて何か考えがありますか?

4

1 に答える 1

1

まず、英単語のトークン定義を追加します

t_plustext    = r'plus'

それらの新しいトークンをに追加しますtokens

tokens = (
    'NAME','NUMBER', 'times', 'divided_by', 'plus', 'minus', 'plustext', ....
)

最後に、これらの新しいトークンを文法で次のように使用します。

def p_expression_binop(p):
    '''expression : expression '+' expression
                  | expression plustext expression
    '''

更新: これは文法の作業サブセットです

#!/usr/bin/python

from __future__ import print_function

import sys
import ply.lex as lex
import ply.yacc as yacc

# ------- Calculator tokenizing rules

tokens = (
    'NUMBER', 'times', 'divided_by', 'plus', 'minus', 'plustext',
    'one', 'two', 'three',
)

literals = ['=','+','-','*','/', '(',')']

t_ignore = " \t\n"

t_plustext    = r'plus'
t_plus    = r'\+'
t_minus   = r'-'
t_times   = r'\*'
t_divided_by  = r'/'
t_one = 'one'
t_two = 'two'
t_three = 'three'

def t_NUMBER(t):
    r'\d+'
    try:
        t.value = int(t.value)
    except ValueError:
        print("Integer value too large %d", t.value)
        t.value = 0
    return t

precedence = (
    ('left','+','-','plustext'),
    ('left','times','divided_by'),
    ('left','*','/'),
)


def p_statement_expr(p):
    'statement : expression'
    p[0] = p[1]
    print(p[1])

def p_expression_binop(p):
    '''expression : expression '+' expression
                  | expression plustext expression
                  | expression '-' expression
                  | expression '*' expression
                  | expression '/' expression'''
    if p[2] ==   '+'  : p[0] = p[1] + p[3]
    elif p[2] == '-': p[0] = p[1] - p[3]
    elif p[2] == '*': p[0] = p[1] * p[3]
    elif p[2] == '/': p[0] = p[1] / p[3]
    elif p[2] == 'plus': p[0] = p[1] + p[3]

def p_statement_lit(p):
    '''expression : NUMBER
          | TXTNUMBER
    '''
    p[0] = p[1]

def p_txtnumber(p):
    '''TXTNUMBER : one
         | two
         | three
    '''
    p[0] = w2n(p[1])

def w2n(s):
    if s == 'one': return 1
    elif s == 'two': return 2
    elif s == 'three': return 3
    assert(False)
    # See http://stackoverflow.com/questions/493174/is-there-a-way-to-convert-number-words-to-integers-python for a complete implementation

def process(data):
    lex.lex()
        yacc.yacc()
        #yacc.parse(data, debug=1, tracking=True)
        yacc.parse(data)

if __name__ == "__main__":
        data = open(sys.argv[1]).read()
        process(data)
于 2013-09-14T14:00:20.300 に答える