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