LoginSignup
0
0

expression.py python用式の評価モジュール

Last updated at Posted at 2024-02-20

pythonで書いた式の評価モジュール
16進整数、10進整数、floatを数として使える。

演算子と優先順位はpythonを基にして次の通り
(expression) 括弧で囲った式
-,~ 負、ビットNOT
*,/ 乗算、整数除算
+,- 加算、減算
<<,>> 左シフト、右シフト
& ビットAND
| ビットOR
' 符号拡張
<=,<,>,>=,!=,== 比較演算子
!x 論理NOT
&& 論理AND
|| 論理OR

'演算子について
a'24とすると、aの24ビット目を符号として符号拡張する。Sign EXtend演算子。世界で初めてのSEX Operatorです。

使い方

import expressionとして、インポートし、
(value,index)=expression.expression(string,0)のように呼び出してください。
stringに式を与え、0は文字列のどこから評価を始めるかのインデックスです。
stringの後ろには番人としてchr(0)を付けておいてください。

valueに式の値が、indexに次のインデックスが返ります。

expression.py
#!/usr/bin/python3
import  sys

vars=[ 0 for i in range(26) ]

def get_vars(s):
    c=ord(s.upper())
    return vars[c-ord('A')]

def put_vars(s,v):
    global vars
    c=ord(s.upper())
    vars[c-ord('A')]=v
    return

def err(m):
    print(m)
    return -1

def factor(s,idx):
    if s[idx]=='-':
        (x,idx)=factor(s,idx+1)
        x=-x
    elif s[idx]=='~':
        (x,idx)=factor(s,idx+1)
        x=~x
    else:
        (x,idx)=factor1(s,idx)
    return (x,idx)

def factor1(s,idx):
    x = 0

    if s[idx]=='0' and (s[idx+1]=='x' or s[idx+1]=='X'):
        idx+=2
        while(s[idx].upper() in "0123456789ABCDEF"):
            x=16*x+(ord(s[idx])-0x30 if s[idx] in "0123456789" else ord(s[idx].upper())-0x41+10 )
            idx+=1

    elif s[idx] in "0123456789":
        while(s[idx] in "0123456789"):
            x=10*x+ord(s[idx])-0x30
            idx+=1
        a=1
        if (s[idx]=='.'):
            idx+=1
            while(s[idx] in "0123456789"):
                x+=(a/10)*(ord(s[idx])-0x30)
                a/=10
                idx+=1

    elif s[idx] in "abcdefghijklmnopqrstuvwxyz":
        x=vars[ord(s[idx].upper())-0x41]
        idx+=1
    elif s[idx]=='(':
        (x,idx)=expression(s,idx+1)
        if s[idx]!=')':
            err("Missing ')'.")
            idx=-1
        else:
            idx+=1
    return (x,idx)

def term0(s,idx):
    (x,idx)=factor(s,idx)
    while True:
        if (s[idx]=='*'):
            (t,idx)=factor(s,idx+1)
            x*=t
        elif (s[idx]=='/'):
            (t,idx)=factor(s,idx+1)
            if t==0:
                err("Division by 0 error.")
                idx=-1
                x=-1
            else:
                x//=t
        elif s[idx]=='%':
            (t,idx)=factor(s,idx+1)
            x=x%t
        else:
            break
    return (x,idx)

def term1(s,idx):
    (x,idx)=term0(s,idx)
    while True:
        if (s[idx]=='+'):
            (t,idx)=term0(s,idx+1)
            x+=t
        elif (s[idx]=='-'):
            (t,idx)=term0(s,idx+1)
            x-=t
        else:
            break
    return (x,idx)

def term2(s,idx):
    (x,idx)=term1(s,idx)
    while True:
        if (s[idx]=='<' and s[idx+1]=='<'):
            (t,idx)=term1(s,idx+2)
            x<<=t
        elif (s[idx]=='>' and s[idx+1]=='>'):
            (t,idx)=term1(s,idx+2)
            x>>=t
        else:
            break
    return (x,idx)

def term3(s,idx):
    (x,idx)=term2(s,idx)
    while True:
        if (s[idx]=='&' and s[idx+1]!='&'):
            (t,idx)=term2(s,idx+1)
            x=int(x)&int(t)
        else:
            break
    return (x,idx)


def term4(s,idx):
    (x,idx)=term3(s,idx)
    while True:
        if (s[idx]=='|' and s[idx+1]!='|'):
            (t,idx)=term3(s,idx+1)
            x=int(x)|int(t)
        else:
            break
    return (x,idx)

def term5(s,idx):
    (x,idx)=term4(s,idx)
    while True:
        if (s[idx]=='^'):
            (t,idx)=term4(s,idx+1)
            x=int(x)^int(t)
        else:
            break
    return (x,idx)

def term6(s,idx):
    (x,idx)=term5(s,idx)
    while True:
        if (s[idx]=='\''):
            (t,idx)=term5(s,idx+1)
            x=(x&~((~0)<<t))|((~0)<<t if (x>>(t-1)&1) else 0)
        else:
            break
    return (x,idx)

def term7(s,idx):
    (x,idx)=term6(s,idx)
    while True:
        if (s[idx]=='<' and s[idx+1]=='='):
            (t,idx)=term6(s,idx+2)
            x=x<=t
        elif (s[idx]=='<'):
            (t,idx)=term6(s,idx+1)
            x=x<t
        elif (s[idx]=='>' and s[idx+1]=='='):
            (t,idx)=term6(s,idx+2)
            x=x>=t
        elif (s[idx]=='>'):
            (t,idx)=term6(s,idx+1)
            x=x>t
        elif (s[idx]=='=' and s[idx+1]=='='):
            (t,idx)=term6(s,idx+2)
            x=x==t
        elif (s[idx]=='!' and s[idx+1]=='='):
            (t,idx)=term6(s,idx+2)
            x=x!=t
        else:
            break
    return (x,idx)

def term8(s,idx):
    if s[idx]=='!':
        (x,idx)=term8(s,idx+1)
        x=not x
    else:
        (x,idx)=term7(s,idx)
    return (x,idx)

def term9(s,idx):
    (x,idx)=term8(s,idx)
    while True:
        if (s[idx]=='&' and s[idx+1]=='&'):
            (t,idx)=term8(s,idx+2)
            x=x and t
        else:
            break
    return (x,idx)

def term10(s,idx):
    (x,idx)=term9(s,idx)
    while True:
        if (s[idx]=='|' and s[idx+1]=='|'):
            (t,idx)=term9(s,idx+2)
            x=x or t
        else:
            break
    return (x,idx)


def expression(s,idx):
    return term10(s,idx)

def main():
    s=input("Input expression:")+chr(0)
    x,idx=expression(s,0)
    print(x)

if __name__=='__main__':
    main()
    exit(0)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0