Mercurial > lcfOS
comparison python/ppci/frontends/ks/parser.py @ 98:3f772feb12ef
movage
author | windel |
---|---|
date | Mon, 24 Dec 2012 13:57:00 +0100 |
parents | python/ppci/frontends/ksparser.py@a350055d6119 |
children | fe145e42259d |
comparison
equal
deleted
inserted
replaced
97:5a965e9664f2 | 98:3f772feb12ef |
---|---|
1 """ | |
2 This module define a grammar for the 'K#' language. | |
3 """ | |
4 | |
5 from .nodes import * | |
6 from .errors import CompilerException, Error | |
7 from .modules import loadModule | |
8 from .display import printNode | |
9 from .builtin import * | |
10 from . import assembler | |
11 | |
12 class Grammar: | |
13 # TODO: implement some base class? | |
14 pass | |
15 | |
16 class Parser: | |
17 #TODO | |
18 pass | |
19 | |
20 class KsParser(Parser): | |
21 def __init__(self): | |
22 self.loadGrammar(KsGrammar) | |
23 | |
24 # For now, try to parse an expression as test case: | |
25 class KsGrammer(Grammar): | |
26 | |
27 def __init__(self): | |
28 pass | |
29 | |
30 # Parsing expressions: | |
31 """ | |
32 grammar of expressions: | |
33 expression = term { addoperator term } | |
34 addoperator = '+' | '-' | |
35 term = factor { muloperator factor } | |
36 muloperator = '*' | '/' | |
37 factor = number | "(" expression ")" | |
38 """ | |
39 | |
40 @rule(Term) | |
41 def Expression1(self, term): | |
42 return Expression(term) | |
43 | |
44 @rule(Term, AddOperator, Term) | |
45 def Expression2(self, term1, op, term2): | |
46 return Expression(term1, op, term2) | |
47 | |
48 # Parsing arithmatic expressions: | |
49 def parseTerm(self): | |
50 a = self.parseFactor() | |
51 while self.token.typ in ['*', '/', 'mod', 'div', 'and']: | |
52 loc = self.getLocation() | |
53 op = self.Consume() | |
54 b = self.parseTerm() | |
55 # Type determination and checking: | |
56 if op in ['mod', 'div']: | |
57 if not isType(a.typ, integer): | |
58 self.Error('First operand should be integer, not {0}'.format(a.typ)) | |
59 if not isType(b.typ, integer): | |
60 self.Error('Second operand should be integer, not {0}'.format(b.typ)) | |
61 typ = integer | |
62 elif op == '*': | |
63 if isType(a.typ, integer) and isType(b.typ, integer): | |
64 typ = integer | |
65 elif isType(a.typ, real) or isType(b.typ, real): | |
66 if isType(a.typ, integer): | |
67 # Automatic type cast | |
68 a = Unop(a, 'INTTOREAL', real) | |
69 if isType(b.typ, integer): | |
70 b = Unop(b, 'INTTOREAL', real) | |
71 if not isType(a.typ, real): | |
72 self.Error('first operand must be a real!') | |
73 if not isType(b.typ, real): | |
74 self.Error('second operand must be a real!') | |
75 typ = real | |
76 else: | |
77 self.Error('Unknown operands for multiply: {0}, {1}'.format(a, b)) | |
78 elif op == '/': | |
79 # Division always yields a real result, for integer division use div | |
80 if isType(a.typ, integer): | |
81 # Automatic type cast | |
82 a = Unop(a, 'INTTOREAL', real) | |
83 if isType(b.typ, integer): | |
84 b = Unop(b, 'INTTOREAL', real) | |
85 if not isType(a.typ, real): | |
86 self.Error('first operand must be a real!') | |
87 if not isType(b.typ, real): | |
88 self.Error('second operand must be a real!') | |
89 typ = real | |
90 elif op == 'and': | |
91 if not isType(a.typ, boolean): | |
92 self.Error('First operand of and must be boolean') | |
93 if not isType(b.typ, boolean): | |
94 self.Error('Second operand of and must be boolean') | |
95 typ = boolean | |
96 else: | |
97 self.Error('Unknown operand {0}'.format(op)) | |
98 | |
99 a = self.setLocation(Binop(a, op, b, typ), loc) | |
100 return a | |
101 | |
102 @rule( | |
103 def parseFactor(self): | |
104 if self.hasConsumed('('): | |
105 e = self.parseExpression() | |
106 self.Consume(')') | |
107 return e | |
108 elif self.token.typ == 'NUMBER': | |
109 loc = self.getLocation() | |
110 val = self.Consume('NUMBER') | |
111 return self.setLocation(Constant(val, integer), loc) | |
112 elif self.token.typ == 'REAL': | |
113 loc = self.getLocation() | |
114 val = self.Consume('REAL') | |
115 return self.setLocation(Constant(val, real), loc) | |
116 elif self.token.typ == 'CHAR': | |
117 val = self.Consume('CHAR') | |
118 return Constant(val, char) | |
119 elif self.token.typ in ['true', 'false']: | |
120 val = self.Consume() | |
121 val = True if val == 'true' else False | |
122 return Constant(val, boolean) | |
123 elif self.hasConsumed('nil'): | |
124 return Constant(0, NilType()) | |
125 elif self.hasConsumed('not'): | |
126 f = self.parseFactor() | |
127 if not isType(f.typ, boolean): | |
128 self.Error('argument of boolean negation must be boolean type') | |
129 return Unop(f, 'not', boolean) | |
130 elif self.token.typ == 'ID': | |
131 designator = self.parseDesignator() | |
132 # TODO: handle functions different here? | |
133 if self.token.typ == '(' and type(designator.typ) is ProcedureType: | |
134 return self.parseProcedureCall(designator) | |
135 else: | |
136 return designator | |
137 else: | |
138 self.Error('Expected NUMBER, ID or ( expr ), got'+str(self.token)) | |
139 | |
140 def parseSimpleExpression(self): | |
141 """ Arithmatic expression """ | |
142 if self.token.typ in ['+', '-']: | |
143 # Handle the unary minus | |
144 op = self.Consume() | |
145 a = self.parseTerm() | |
146 typ = a.typ | |
147 if not isType(typ,real) and not isType(typ, integer): | |
148 self.Error('Unary minus or plus can be only applied to real or integers') | |
149 if op == '-': | |
150 a = Unop(a, op, typ) | |
151 else: | |
152 a = self.parseTerm() | |
153 while self.token.typ in ['+', '-', 'or']: | |
154 loc = self.getLocation() | |
155 op = self.Consume() | |
156 b = self.parseTerm() | |
157 if op in ['+', '-']: | |
158 if isType(a.typ, real) or isType(b.typ, real): | |
159 typ = real | |
160 if isType(a.typ, integer): | |
161 # Automatic type cast | |
162 a = Unop(a, 'INTTOREAL', real) | |
163 if not isType(a.typ, real): | |
164 self.Error('first operand must be a real!') | |
165 if isType(b.typ, integer): | |
166 b = Unop(b, 'INTTOREAL', real) | |
167 if not isType(b.typ, real): | |
168 self.Error('second operand must be a real!') | |
169 elif isType(a.typ, integer) and isType(b.typ, integer): | |
170 typ = integer | |
171 else: | |
172 self.Error('Invalid types {0} and {1}'.format(a.typ, b.typ)) | |
173 elif op == 'or': | |
174 if not isType(a.typ, boolean): | |
175 self.Error('first operand must be boolean for or operation') | |
176 if not isType(b.typ, boolean): | |
177 self.Error('second operand must be boolean for or operation') | |
178 typ = boolean | |
179 else: | |
180 self.Error('Unknown operand {0}'.format(op)) | |
181 a = self.setLocation(Binop(a, op, b, typ), loc) | |
182 return a | |
183 |