From abc0421ad745cb62629e837439b0bfd7f3165c44 Mon Sep 17 00:00:00 2001 From: portnov Date: Sun, 14 Dec 2008 13:56:30 +0500 Subject: [PATCH] Allow variables in input, such as "A(3,y)". --- data.py | 31 ++++++++++++++++--- lexer.py | 11 +++++-- parser.out | 94 ++++++++++++++++++++++++++++++++++++++++------------------ parsetab.py | 8 +++-- syntax.py | 13 ++++++-- 5 files changed, 114 insertions(+), 43 deletions(-) diff --git a/data.py b/data.py index a8b704f..5008fdd 100644 --- a/data.py +++ b/data.py @@ -71,28 +71,44 @@ class NothingClass(object): Nothing = NothingClass() class Unknown(object): - def __init__(self,name='',add=True): + def __init__(self,name='',add=True,value=None): self.name = name if add: - unknowns[name] = None + unknowns[name] = value def __repr__(self): return self.name def __add__(self,e): + if is_number(e) and e==0: + return self return Expr('+',self,e) def __sub__(self,e): return self + Expr('*',-1,e) def __mul__(self,e): + if is_number(e) and e==1: + return self return Expr('*',self,e) + + def __pow__(self,e): + if is_number(e) and e==1.0: + return self + return Expr('^', self,e) + + def __div__(self,e): + if is_number(e) and e==1: + return self + return Expr('/',self,e) class Const(float): def __init__(self,x): float.__init__(self,x) def __add__(self,e): + if self == 0: + return e if is_number(e): return float.__add__(self,e) if is_nothing(e): @@ -112,6 +128,8 @@ class Const(float): return self + Expr('*',-1,e) def __mul__(self,e): + if self == 1.0: + return e if is_number(e): return float.__mul__(self,e) if is_nothing(e): @@ -147,11 +165,11 @@ def line_by_two_points(A,B): class Point(object): def __init__(self,name,x,y): - if isinstance(x, Unknown): + if isinstance(x, Unknown) and not x.name: self.x = Unknown(name+'x') else: self.x = x - if isinstance(y, Unknown): + if isinstance(y, Unknown) and not y.name: self.y = Unknown(name+'y') else: self.y = y @@ -321,7 +339,10 @@ class Expr(object): return Expr('+',self,e) def __sub__(self,e): - return self + Expr('*',-1,e) + return self + Expr('*',Const(-1),e) + + def __neg__(self): + return Expr('*',Const(-1),self) def __mul__(self,e): if is_number(e): diff --git a/lexer.py b/lexer.py index a87aaf7..e5c0d02 100644 --- a/lexer.py +++ b/lexer.py @@ -1,13 +1,13 @@ from ply import lex -from data import Const +from data import Const, Unknown -tokens = ('POINT','SEGMENT', 'IN', 'PARAL', 'PERP', 'EQ', 'PARENL', 'PARENR', 'COMMA','NUMBER') +tokens = ('POINT','SEGMENT', 'IN', 'PARAL', 'PERP', 'EQ', 'PARENL', 'PARENR', 'COMMA','NUMBER','VAR') t_POINT = '[A-Z]' t_SEGMENT = '[A-Z][A-Z]' -t_IN = 'in' +t_IN = '<-' t_PARAL = '\|\|' t_PERP = '_\|_' t_EQ = '=' @@ -24,4 +24,9 @@ def t_NUMBER(t): t.value = Const(t.value) return t +def t_VAR(t): + "[a-z][0-9]?" + t.value = Unknown(t.value,value=Unknown(t.value)) + return t + lex.lex() diff --git a/parser.out b/parser.out index 3c78c00..9c8f278 100644 --- a/parser.out +++ b/parser.out @@ -10,27 +10,31 @@ Rule 2 statement -> SEGMENT PARAL SEGMENT Rule 3 statement -> SEGMENT PERP SEGMENT Rule 4 statement -> POINT IN SEGMENT Rule 5 statement -> SEGMENT EQ SEGMENT -Rule 6 statement -> SEGMENT EQ NUMBER -Rule 7 statement -> POINT PARENL NUMBER COMMA NUMBER PARENR +Rule 6 statement -> SEGMENT EQ value +Rule 7 statement -> POINT PARENL value COMMA value PARENR +Rule 8 value -> NUMBER +Rule 9 value -> VAR Terminals, with rules where they appear COMMA : 7 EQ : 5 6 IN : 4 -NUMBER : 6 7 7 +NUMBER : 8 PARAL : 2 PARENL : 7 PARENR : 7 PERP : 3 POINT : 4 7 SEGMENT : 2 2 3 3 4 5 5 6 +VAR : 9 error : Nonterminals, with rules where they appear generic : 0 statement : 1 +value : 6 7 7 Parsing method: LALR @@ -44,8 +48,8 @@ state 0 (3) statement -> . SEGMENT PERP SEGMENT (4) statement -> . POINT IN SEGMENT (5) statement -> . SEGMENT EQ SEGMENT - (6) statement -> . SEGMENT EQ NUMBER - (7) statement -> . POINT PARENL NUMBER COMMA NUMBER PARENR + (6) statement -> . SEGMENT EQ value + (7) statement -> . POINT PARENL value COMMA value PARENR SEGMENT shift and go to state 4 POINT shift and go to state 1 @@ -57,7 +61,7 @@ state 0 state 1 (4) statement -> POINT . IN SEGMENT - (7) statement -> POINT . PARENL NUMBER COMMA NUMBER PARENR + (7) statement -> POINT . PARENL value COMMA value PARENR IN shift and go to state 5 PARENL shift and go to state 6 @@ -84,7 +88,7 @@ state 4 (2) statement -> SEGMENT . PARAL SEGMENT (3) statement -> SEGMENT . PERP SEGMENT (5) statement -> SEGMENT . EQ SEGMENT - (6) statement -> SEGMENT . EQ NUMBER + (6) statement -> SEGMENT . EQ value PARAL shift and go to state 9 PERP shift and go to state 8 @@ -102,27 +106,35 @@ state 5 state 6 - (7) statement -> POINT PARENL . NUMBER COMMA NUMBER PARENR + (7) statement -> POINT PARENL . value COMMA value PARENR + (8) value -> . NUMBER + (9) value -> . VAR NUMBER shift and go to state 11 + VAR shift and go to state 13 + value shift and go to state 12 state 7 (5) statement -> SEGMENT EQ . SEGMENT - (6) statement -> SEGMENT EQ . NUMBER + (6) statement -> SEGMENT EQ . value + (8) value -> . NUMBER + (9) value -> . VAR - SEGMENT shift and go to state 12 - NUMBER shift and go to state 13 + SEGMENT shift and go to state 14 + NUMBER shift and go to state 11 + VAR shift and go to state 13 + value shift and go to state 15 state 8 (3) statement -> SEGMENT PERP . SEGMENT - SEGMENT shift and go to state 14 + SEGMENT shift and go to state 16 @@ -130,7 +142,7 @@ state 9 (2) statement -> SEGMENT PARAL . SEGMENT - SEGMENT shift and go to state 15 + SEGMENT shift and go to state 17 @@ -144,64 +156,88 @@ state 10 state 11 - (7) statement -> POINT PARENL NUMBER . COMMA NUMBER PARENR + (8) value -> NUMBER . - COMMA shift and go to state 16 + $end reduce using rule 8 (value -> NUMBER .) + PARENR reduce using rule 8 (value -> NUMBER .) + COMMA reduce using rule 8 (value -> NUMBER .) state 12 - (5) statement -> SEGMENT EQ SEGMENT . + (7) statement -> POINT PARENL value . COMMA value PARENR - $end reduce using rule 5 (statement -> SEGMENT EQ SEGMENT .) + COMMA shift and go to state 18 state 13 - (6) statement -> SEGMENT EQ NUMBER . + (9) value -> VAR . - $end reduce using rule 6 (statement -> SEGMENT EQ NUMBER .) + $end reduce using rule 9 (value -> VAR .) + PARENR reduce using rule 9 (value -> VAR .) + COMMA reduce using rule 9 (value -> VAR .) state 14 - (3) statement -> SEGMENT PERP SEGMENT . + (5) statement -> SEGMENT EQ SEGMENT . - $end reduce using rule 3 (statement -> SEGMENT PERP SEGMENT .) + $end reduce using rule 5 (statement -> SEGMENT EQ SEGMENT .) state 15 - (2) statement -> SEGMENT PARAL SEGMENT . + (6) statement -> SEGMENT EQ value . - $end reduce using rule 2 (statement -> SEGMENT PARAL SEGMENT .) + $end reduce using rule 6 (statement -> SEGMENT EQ value .) state 16 - (7) statement -> POINT PARENL NUMBER COMMA . NUMBER PARENR + (3) statement -> SEGMENT PERP SEGMENT . - NUMBER shift and go to state 17 + $end reduce using rule 3 (statement -> SEGMENT PERP SEGMENT .) state 17 - (7) statement -> POINT PARENL NUMBER COMMA NUMBER . PARENR + (2) statement -> SEGMENT PARAL SEGMENT . - PARENR shift and go to state 18 + $end reduce using rule 2 (statement -> SEGMENT PARAL SEGMENT .) state 18 - (7) statement -> POINT PARENL NUMBER COMMA NUMBER PARENR . + (7) statement -> POINT PARENL value COMMA . value PARENR + (8) value -> . NUMBER + (9) value -> . VAR + + NUMBER shift and go to state 11 + VAR shift and go to state 13 + + + value shift and go to state 19 + +state 19 + + (7) statement -> POINT PARENL value COMMA value . PARENR + + PARENR shift and go to state 20 + + + +state 20 + + (7) statement -> POINT PARENL value COMMA value PARENR . - $end reduce using rule 7 (statement -> POINT PARENL NUMBER COMMA NUMBER PARENR .) + $end reduce using rule 7 (statement -> POINT PARENL value COMMA value PARENR .) diff --git a/parsetab.py b/parsetab.py index 1b9b4ff..c5eca60 100644 --- a/parsetab.py +++ b/parsetab.py @@ -4,9 +4,9 @@ _lr_method = 'LALR' -_lr_signature = "'K\xe1\xf4\xb9.`<\x83\xcc:]\xa6\xcb\xff\xc5" +_lr_signature = '\x92\x98\x85\xb9]z\xf7\x14\x8c\xbe\xd7pE\xaeh2' -_lr_action_items = {'PARENR':([17,],[18,]),'POINT':([0,],[1,]),'EQ':([4,],[7,]),'NUMBER':([6,7,16,],[11,13,17,]),'PARAL':([4,],[9,]),'PERP':([4,],[8,]),'COMMA':([11,],[16,]),'IN':([1,],[5,]),'SEGMENT':([0,5,7,8,9,],[4,10,12,14,15,]),'PARENL':([1,],[6,]),'$end':([2,3,10,12,13,14,15,18,],[0,-1,-4,-5,-6,-3,-2,-7,]),} +_lr_action_items = {'PARENR':([11,13,19,],[-8,-9,20,]),'POINT':([0,],[1,]),'EQ':([4,],[7,]),'NUMBER':([6,7,18,],[11,11,11,]),'PARAL':([4,],[9,]),'PERP':([4,],[8,]),'COMMA':([11,12,13,],[-8,18,-9,]),'IN':([1,],[5,]),'VAR':([6,7,18,],[13,13,13,]),'SEGMENT':([0,5,7,8,9,],[4,10,14,16,17,]),'PARENL':([1,],[6,]),'$end':([2,3,10,11,13,14,15,16,17,20,],[0,-1,-4,-8,-9,-5,-6,-3,-2,-7,]),} _lr_action = { } for _k, _v in _lr_action_items.items(): @@ -15,7 +15,7 @@ for _k, _v in _lr_action_items.items(): _lr_action[_x][_k] = _y del _lr_action_items -_lr_goto_items = {'generic':([0,],[2,]),'statement':([0,],[3,]),} +_lr_goto_items = {'generic':([0,],[2,]),'value':([6,7,18,],[12,15,19,]),'statement':([0,],[3,]),} _lr_goto = { } for _k, _v in _lr_goto_items.items(): @@ -32,4 +32,6 @@ _lr_productions = [ ('statement',3,'p_statement_eq_s','syntax.py',31), ('statement',3,'p_statement_eq_n','syntax.py',37), ('statement',6,'p_statement_point','syntax.py',43), + ('value',1,'p_value_number','syntax.py',48), + ('value',1,'p_value_var','syntax.py',52), ] diff --git a/syntax.py b/syntax.py index 8d113cd..66ea126 100644 --- a/syntax.py +++ b/syntax.py @@ -34,16 +34,23 @@ def p_statement_eq_s(t): t[0] = c def p_statement_eq_n(t): - "statement : SEGMENT EQ NUMBER" + "statement : SEGMENT EQ value" c = Condition(COND_EQ, segment(t[1]), t[3]) conditions.append(c) t[0] = c def p_statement_point(t): - "statement : POINT PARENL NUMBER COMMA NUMBER PARENR" + "statement : POINT PARENL value COMMA value PARENR" p = Point(t[1],t[3],t[5]) points[t[1]] = p - return p + +def p_value_number(t): + "value : NUMBER" + t[0] = t[1] + +def p_value_var(t): + "value : VAR" + t[0] = t[1] yacc.yacc() -- 1.7.2.3