構文解析 (parsing)
概要
文字列の式等を LL(1) で構文解析しながら計算を行う。
実装 (AOJ 0264)
あるMOD上で 四則演算 + カッコ が含まれる式を計算する。
# MOD上で 四則演算 + カッコ を処理する
#
# -- 文法規則 --
# S -> E
# E -> E '+' T | E '-' T | T
# T -> T '*' F | T '/' F | F
# F -> N | '(' E ')'
# N -> <数値>
def calc(S, MOD):
L = len(S)
S = S + "$"
ok = 1
cur = 0
# E -> E '+' T | E '-' T | T
def expr():
nonlocal cur
op = "+"
res = 0
while cur < L:
val = term()
if op == "+":
res += val
else: # '-'
res -= val
res %= MOD
if S[cur] not in "+-":
break
op = S[cur]
cur += 1 # '+' or '-'
return res
# T -> T '*' F | T '/' F | F
def term():
nonlocal cur, ok
op = "*"
res = 1
while cur < L:
val = factor()
if op == "*":
res *= val
else: # '/'
if val == 0:
ok = 0
res *= pow(val, MOD-2, MOD)
res %= MOD
if S[cur] not in "*/":
break
op = S[cur]
cur += 1 # '*' or '/'
return res
# F -> N | '(' E ')'
def factor():
nonlocal cur
if S[cur] == '(':
cur += 1 # '('
val = expr()
cur += 1 # ')'
return val
return number()
# N -> <数値>
def number():
nonlocal cur
val = 0
while S[cur] in "0123456789":
val = (10*val + int(S[cur])) % MOD
cur += 1 # '0123456789'
return val
res = expr()
return res if ok else -1
# example:
# calc('100', 6) = 4
# calc('10*3/7+(50+81/22)+11', 1153) = 915
Verified
-
AOJ: "0264: Finite Field Calculator": source (Python3, 0.69sec)