70
|
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
|