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