#!/usr/bin/env python
-- coding: utf-8 --
from math import *
from operator import *
import re
from expr import Var,Number,Expr
""" 把
a=1+b+c^2
c=2
b=c+2
这样的一行一行,分成
ID ASSIGN ADD ID ADD EQ POW 2 EOL
ID ASSIGN 2 EOL
ID ASSIGN ID ADD 2 EOL
这样的一行一行token,
输出是一行一个token list的形式
token分为如下几类:
1.+,-,*,/,^,=,(,),, 算术运算符
2.==,>=,>,<=,<,!= 逻辑运算符
3.[0-9]+.[0-9]*[Ee][+-]?[0-9]+ [0-9]+ 字面浮点数和整数
4.[a-zA-Z_]+ 变量或函数名称标识符
5.[ \t\n] 忽略,或结束
由于使用正则表达式直接匹配,所以和flex不同的是:
无法确保当有多个匹配项时,最长优先,因此,只能利用先后顺序解决冲突,
因而必须把==放在=前面。
"""
logic_op_re=re.compile(r'==|>=|>|<=|<|!=')
number_re =re.compile(r'[+-]?[0-9]+.?[0-9]*[Ee]?[+-]?[0-9]?')
arith_op_re=re.compile(r'+|-|*|/|^|=|(|)|,')
int_re =re.compile(r'[0-9]+')
id_re =re.compile(r'[a-zA-Z_]+')
blank_re =re.compile(r'[\ |\t|\r]+')
comment_re =re.compile(r'"([^"]*)"')
other_re =re.compile(r'.+')
def scanner(line):
result=[]
while True:
line=line.strip()
if not line:
return result
m=re.match(logic_op_re,line)
if m:
result.append(('logic_op',m.group()))
line=line[m.end():]
continue
m=re.match(number_re ,line)
if m:
result.append(('number',float(m.group())))
line=line[m.end():]
continue
m=re.match(arith_op_re,line)
if m:
result.append(('arith_op',m.group()))
line=line[m.end():]
continue
m=re.match(int_re ,line)
if m:
result.append(('number',float(m.group())))
line=line[m.end():]
continue
m=re.match(id_re ,line)
if m:
result.append(('id',m.group()))
line=line[m.end():]
continue
m=re.match(comment_re ,line)
if m:
result.append(('comment',m.group()))
line=line[m.end():]
continue
m=re.match(blank_re ,line)
if m:
line=line[m.end():]
continue
m=re.match(other_re,line)
if m:
print "亲,看看你都塞了一堆什么进来呀?\""+m.group()+"\" 人家好伤心的呀!"
line=line[m.end():]
return result
class Parser(object):
""" 文法分析: """
input_file=None
env=None
def __init__(self,env):
self.env=env
def parse(self,input_file):
"""
如入可以是sys.stdin,a file,a string
要求实现readline()方法
"""
self.input_file=input_file
self.run()
def run(self):
while True:
line=self.input_file.readline()
if not line:
return
tokens=scanner(line)
#把字母名称的函数标示出来
r=[]
for t in tokens:
if t[0]=='id' and self.env.get_function(t[1]):
r.append(('function',t[1]))
else:
r.append(t)
tokens=r
#把comment提取出来
comments=map(lambda x:x[1],
filter(lambda x:x[0]=="comment",tokens))
comments=' '.join(comments)
tokens=filter(lambda x:x[0]!="comment",tokens)
#含有=的表达式是约束方程,其它的都是expr
c=tokens.count( ('arith_op', '='))
if c==0:
#没有约束到变量的表达式
e=self.parse_expr(tokens)
#e.set_desc(comments)
self.env.add_expr(e)
continue
if c>1:
print "亲,赋值一次就够了,你肿么赋值了"+str(c)+"次涅?"
continue
#c=1
if len(tokens)<3 or tokens[0][0]!='id' or \
tokens[1]!=('arith_op','='):
print "亲,你给我的表达式格式有问题偶~:"+line
continue
var_name=tokens[0][1]
var=self.env.get_variable(var_name)
if var is None:
var=Var(var_name,comments)
self.env.set_variable(var_name,var)
e=self.parse_expr(tokens[2:])
var.set_expr(e)
def parse_expr(self,tokens):
"""
token分为如下几类:
1.+,-,*,/,^,=,(,),, 算术运算符
2.==,>=,>,<=,<,!= 逻辑运算符
3.[0-9]+\.[0-9]*[Ee][+-]?[0-9]+ [0-9]+ 字面浮点数和整数
4.[a-zA-Z_]+ 变量或函数名称标识符
5.[ \\t\\n] 忽略,或结束
BNF:
expr=expr[==|>=|>|<=|<|!=]expr|expr
expr=expr+expr | expr-expr
expr=expr*expr | expr/expr
expr=expr^expr
expr=function(expr[,expr])
expr=(expr)
expr=<float>|<var>
"""
if len(tokens):
expr,rest=self.parse_logic_op(tokens)
return expr
#能处理就处理,不能处理原样返回。
def parse_logic_op(self,tokens):
left,rest=self.parse_add_sub_op(tokens)
if not len(rest):
return left,rest
logic_op_list=["==",">=",">","<=","<","!="]
if rest[0][1] not in logic_op_list:
return left,rest
op=self.env.get_function(rest[0][1])
right,rest=self.parse_add_sub_op(rest[1:])
return Expr(op,[left,right]),rest
def parse_add_sub_op(self,tokens):
left,rest=self.parse_mul_div_op(tokens)
add_sub_op_list=["+","-"]
while len(rest) and rest[0][1] in add_sub_op_list:
op=self.env.get_function(rest[0][1])
right,rest=self.parse_mul_div_op(rest[1:])
left=Expr(op,[left,right])
return left,rest
def parse_mul_div_op(self,tokens):
left,rest=self.parse_pow_op(tokens)
mul_div_op_list=["*","/"]
while len(rest) and rest[0][1] in mul_div_op_list:
op=self.env.get_function(rest[0][1])
right,rest=self.parse_pow_op(rest[1:])
left=Expr(op,[left,right])
return left,rest
def parse_pow_op(self,tokens):
left,rest=self.parse_function_op(tokens)
pow_op_list=["^"]
while len(rest) and (rest[0][1] in pow_op_list):
op=self.env.get_function(rest[0][1])
right,rest=self.parse_pow_op(rest[1:])
left=Expr(op,[left,right])
return left,rest
def parse_function_op(self,tokens):
if tokens[0][0] in ['number','id']:
return self.parse_float_var_op(tokens)
if tokens[0][1]=='(':
return self.parse_parentheses_op(tokens)
if tokens[0][0]!='function':
return None,tokens
op=self.env.get_function(tokens[0][1])
if op and tokens[1][1]=='(':
paras=[]
tokens=tokens[2:]
left,tokens=self.parse_add_sub_op(tokens)
paras.append(left)
while tokens[0][1]==',':
left,tokens=self.parse_add_sub_op(tokens[1:])
paras.append(left)
if tokens[0][1]==')':
tokens=tokens[1:]
else:
print "bad syntax. tokens found ->",tokens
expr=Expr(op,paras)
return expr,tokens
else:
print "error bad syntax ->",tokens
return None,tokens
def parse_parentheses_op(self,tokens):
if tokens[0][1]=='(':
left,tokens=self.parse_logic_op(tokens[1:])
if tokens[0][1]==')':
return left,tokens[1:]
return left,tokens
return None,tokens
def parse_float_var_op(self,tokens):
if tokens[0][0] == 'number':
n=Number(tokens[0][1])
return n,tokens[1:]
if tokens[0][0] == 'id':
var=self.env.get_variable(tokens[0][1])
if not var:
var_name=tokens[0][1]
var=Var(var_name,'')
self.env.set_variable(var_name,var)
var=self.env.get_variable(tokens[0][1])
return var,tokens[1:]
return None,tokens
import StringIO
from env import *
def test():
s=""" a=1+(b+c)^2/23.1e-10 "变量a"
c=2 "变量c" "c是个好变量"
b=c+2 "变量b" "b也是个好变量" "这是为它写的第三条注释"
a>c "检查a是否大于c"
a>=c "检查a是否大于等于c"
run
dump
c=3 "change c again."
"注释也可以在前面" c^2>=sin(pow(a,b)+b)
run
dump
"""
#for l in s.split('\n'):
# scanner(l)
print "+"*80
print '*'*70
print s
print '*'*70
e=Env()
i=StringIO.StringIO(s)
e.exec_stream(i)
print "+"*80
if name=="main":
test()