author | Richard Taylor <richard.i.taylor@nokia.com> |
Tue, 04 May 2010 14:01:37 +0100 | |
branch | wip |
changeset 509 | a337b022f8a8 |
parent 369 | 1248e8f6a72d |
permissions | -rwxr-xr-x |
3 | 1 |
# |
369
1248e8f6a72d
Updated copright year on modified files.
Stefan Karlsson <stefan.karlsson@nokia.com>
parents:
368
diff
changeset
|
2 |
# Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). |
3 | 3 |
# All rights reserved. |
4 |
# This component and the accompanying materials are made available |
|
5 |
# under the terms of the License "Eclipse Public License v1.0" |
|
6 |
# which accompanies this distribution, and is available |
|
7 |
# at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 |
# |
|
9 |
# Initial Contributors: |
|
10 |
# Nokia Corporation - initial contribution. |
|
11 |
# |
|
12 |
# Contributors: |
|
13 |
# |
|
14 |
# Description: |
|
15 |
# MMPParser module |
|
16 |
# This module provides a parser for MMP files which can work |
|
17 |
# with any supplied MMPBackend |
|
18 |
# |
|
19 |
||
20 |
||
21 |
# We have to define the grammar in the following order: |
|
22 |
# Actions - because the rules reference them |
|
23 |
# Terminals - because the rules use them |
|
24 |
# Rules |
|
25 |
# Root rule - e.g. "an MMP is a list of statements" |
|
26 |
# |
|
27 |
# This seems inverted but it's just the price of |
|
28 |
# being able to use python to define the grammar. |
|
29 |
||
30 |
||
31 |
from pyparsing import * |
|
32 |
import sys |
|
33 |
||
34 |
# For multiline matching we must exclude \n from the list of whitespace |
|
35 |
# characters. If we don't then Parse Elements like OneOrMore won't stop |
|
36 |
# at line boundaries. |
|
37 |
# \r doesn't matter as it is always followed by \n anyhow it is |
|
38 |
# redundant and may be thrown away without any loss of information. |
|
39 |
ParserElement.setDefaultWhitespaceChars('\t\r ') |
|
40 |
||
41 |
||
42 |
||
43 |
||
44 |
## Useful Parse Elements ######################################### |
|
45 |
def String(): |
|
46 |
return Regex('[^ \n]+') |
|
47 |
||
48 |
def StringList(): |
|
49 |
return Group(OneOrMore(Regex('[^ \n]+'))) |
|
50 |
||
51 |
def HexOrDecNumber(): |
|
52 |
return Regex('(0[xX][0-9a-fA-Z]+)|([0-9]+)') |
|
53 |
||
54 |
def Line(pattern): |
|
55 |
return pattern.copy() + LineEnd().suppress() |
|
56 |
||
57 |
||
58 |
||
59 |
class MMPParser(object): |
|
60 |
# Tools for whom options may be specified |
|
61 |
tools = [ 'ARMCC', 'CW', 'GCC', 'MSVC', 'GCCXML', 'ARMASM', 'GCCE' ] |
|
62 |
||
63 |
||
64 |
def __init__(self,statemachine): |
|
65 |
self.backend = statemachine |
|
66 |
# Create Tokens for the tools we support |
|
67 |
self.toolName = CaselessKeyword(MMPParser.tools[0]) |
|
68 |
for thisTool in MMPParser.tools[1:]: |
|
69 |
self.toolName ^= CaselessKeyword(thisTool) |
|
70 |
||
71 |
self.assignment = \ |
|
72 |
( \ |
|
73 |
Line(CaselessKeyword('ARMFPU') + String()) ^ \ |
|
9 | 74 |
Line(CaselessKeyword('APPLY') + String()) ^ \ |
3 | 75 |
Line(CaselessKeyword('ASSPLIBRARY') + StringList()) ^ \ |
76 |
Line(CaselessKeyword('CAPABILITY') + StringList()) ^ \ |
|
77 |
Line(CaselessKeyword('DOCUMENT') + StringList()) ^ \ |
|
78 |
Line(CaselessKeyword('EPOCHEAPSIZE') + HexOrDecNumber() + HexOrDecNumber()) ^ \ |
|
79 |
Line(CaselessKeyword('EPOCPROCESSPRIORITY') + String()) ^ \ |
|
80 |
Line(CaselessKeyword('FIRSTLIB') + String()) ^ \ |
|
81 |
Line(CaselessKeyword('TARGET') + String()) ^ \ |
|
82 |
Line(CaselessKeyword('ROMTARGET') + Optional(StringList())) ^ \ |
|
83 |
Line(CaselessKeyword('RAMTARGET') + String()) ^ \ |
|
84 |
Line(CaselessKeyword('TARGETTYPE') + String()) ^ \ |
|
85 |
Line(CaselessKeyword('TARGETPATH') + String()) ^ \ |
|
86 |
Line(CaselessKeyword('SYSTEMINCLUDE') + StringList()) ^ \ |
|
87 |
Line(CaselessKeyword('USERINCLUDE') + StringList()) ^ \ |
|
88 |
Line(CaselessKeyword('DEFFILE') + String()) ^ \ |
|
89 |
Line(CaselessKeyword('EXPORTLIBRARY') + String()) ^ \ |
|
90 |
Line(CaselessKeyword('LINKAS') + String()) ^ \ |
|
91 |
Line(CaselessKeyword('VENDORID') + HexOrDecNumber()) ^ \ |
|
92 |
Line(CaselessKeyword('OPTION') + self.toolName + StringList()) ^ \ |
|
93 |
Line(CaselessKeyword('LINKEROPTION') + self.toolName + StringList()) ^\ |
|
94 |
Line(CaselessKeyword('OPTION_REPLACE') + self.toolName + StringList()) ^ \ |
|
95 |
Line(CaselessKeyword('SECUREID') + HexOrDecNumber()) ^ \ |
|
96 |
Line(CaselessKeyword('EPOCSTACKSIZE') + HexOrDecNumber()) ^ \ |
|
97 |
Line(CaselessKeyword('VERSION') + String() + Optional(CaselessKeyword('EXPLICIT'))) ^ \ |
|
98 |
Line(CaselessKeyword('EPOCPROCESSPRIORITY') + String()) ^ \ |
|
99 |
Line(CaselessKeyword('NEWLIB') + String()) \ |
|
100 |
).setParseAction(self.backend.doAssignment) ^ \ |
|
101 |
( \ |
|
102 |
Line(CaselessKeyword('SOURCE') + StringList()).setParseAction(self.backend.doSourceAssignment) \ |
|
103 |
).setParseAction(self.backend.doSourceAssignment) ^ \ |
|
104 |
( \ |
|
105 |
Line(CaselessKeyword('RESOURCE') + StringList()).setParseAction(self.backend.doOldResourceAssignment) \ |
|
106 |
).setParseAction(self.backend.doOldResourceAssignment) ^ \ |
|
107 |
( \ |
|
108 |
Line(CaselessKeyword('SYSTEMRESOURCE') + StringList()).setParseAction(self.backend.doResourceAssignment) \ |
|
109 |
).setParseAction(self.backend.doOldResourceAssignment) ^ \ |
|
110 |
( \ |
|
111 |
Line(CaselessKeyword('SOURCEPATH') + String()).setParseAction(self.backend.doSourceAssignment) \ |
|
112 |
).setParseAction(self.backend.doSourcePathAssignment) ^ \ |
|
113 |
( \ |
|
114 |
Line((CaselessKeyword('UID') + Group(HexOrDecNumber() + Optional(HexOrDecNumber())))).setParseAction(self.backend.doUIDAssignment) \ |
|
115 |
).setParseAction(self.backend.doUIDAssignment) ^ \ |
|
116 |
( \ |
|
117 |
Line(CaselessKeyword('LANG') + StringList()) \ |
|
118 |
).setParseAction(self.backend.doAppend) ^ \ |
|
119 |
( \ |
|
120 |
Line(CaselessKeyword('LIBRARY') + StringList()) \ |
|
121 |
).setParseAction(self.backend.doAppend) ^ \ |
|
122 |
( \ |
|
123 |
Line(CaselessKeyword('DEBUGLIBRARY') + StringList()) \ |
|
124 |
).setParseAction(self.backend.doAppend) ^ \ |
|
125 |
( \ |
|
126 |
Line(CaselessKeyword('MACRO') + Optional(StringList())) \ |
|
127 |
).setParseAction(self.backend.doAppend) ^ \ |
|
128 |
( \ |
|
129 |
Line(CaselessKeyword('AIF') + StringList()) \ |
|
130 |
).setParseAction(self.backend.doDeprecated) ^ \ |
|
131 |
( \ |
|
132 |
Line(CaselessKeyword('STATICLIBRARY') + StringList()) \ |
|
133 |
).setParseAction(self.backend.doAppend) |
|
134 |
||
135 |
self.switch = \ |
|
136 |
(Line( \ |
|
137 |
CaselessKeyword('ALWAYS_BUILD_AS_ARM') ^ \ |
|
138 |
CaselessKeyword('ASSPEXPORTS') ^ \ |
|
139 |
CaselessKeyword('ASSPABI') ^ \ |
|
140 |
CaselessKeyword('ASSPEXPORTS') ^ \ |
|
141 |
CaselessKeyword('DEBUGGABLE') ^ \ |
|
142 |
CaselessKeyword('DEBUGGABLE_UDEBONLY') ^ \ |
|
143 |
CaselessKeyword('EPOCALLOWDLLDATA') ^ \ |
|
144 |
CaselessKeyword('EPOCCALLDLLENTRYPOINTS') ^ \ |
|
145 |
CaselessKeyword('EPOCFIXEDPROCESS') ^ \ |
|
368
113d720d5a6c
Added test case for EPOCNESTEDEXCEPTIONS.
Stefan Karlsson <stefan.karlsson@nokia.com>
parents:
9
diff
changeset
|
146 |
CaselessKeyword('EPOCNESTEDEXCEPTIONS') ^ \ |
3 | 147 |
CaselessKeyword('EXPORTUNFROZEN') ^ \ |
148 |
CaselessKeyword('FEATUREVARIANT') ^ \ |
|
149 |
CaselessKeyword('BYTEPAIRCOMPRESSTARGET') ^ \ |
|
150 |
CaselessKeyword('INFLATECOMPRESSTARGET') ^ \ |
|
151 |
CaselessKeyword('NOCOMPRESSTARGET') ^ \ |
|
152 |
CaselessKeyword('NOLINKTIMECODEGENERATION') ^ \ |
|
153 |
CaselessKeyword('NOMULTIFILECOMPILATION') ^ \ |
|
154 |
CaselessKeyword('COMPRESSTARGET') ^ \ |
|
155 |
CaselessKeyword('NOEXPORTLIBRARY') ^ \ |
|
156 |
CaselessKeyword('NOSTRICTDEF') ^ \ |
|
157 |
CaselessKeyword('SRCDBG') ^ \ |
|
158 |
CaselessKeyword('STRICTDEPEND') ^ \ |
|
159 |
CaselessKeyword('STDCPP') ^ \ |
|
160 |
CaselessKeyword('NOSTDCPP') ^ \ |
|
161 |
CaselessKeyword('SMPSAFE') ^ \ |
|
162 |
CaselessKeyword('PAGED') ^ \ |
|
163 |
CaselessKeyword('PAGEDCODE') ^ \ |
|
164 |
CaselessKeyword('PAGEDDATA') ^ \ |
|
165 |
CaselessKeyword('UNPAGED') ^ \ |
|
166 |
CaselessKeyword('UNPAGEDCODE') ^ \ |
|
167 |
CaselessKeyword('UNPAGEDDATA') ^ \ |
|
168 |
CaselessKeyword('WCHARENTRYPOINT') \ |
|
169 |
)).setParseAction(self.backend.doSetSwitch) |
|
170 |
||
171 |
# General |
|
172 |
||
173 |
self.blankline = (LineStart() + Regex('[\t\r ]*') + LineEnd().suppress() \ |
|
174 |
).setParseAction(self.backend.doBlankLine) |
|
175 |
||
176 |
self.preProcessorComment = (LineStart() + Regex('# .*') + LineEnd().suppress() |
|
177 |
).setParseAction(self.backend.doPreProcessorComment) |
|
178 |
||
179 |
self.unknownstatement = (LineStart() + Regex('.*\S+') + LineEnd().suppress() \ |
|
180 |
).setParseAction(self.backend.doUnknownStatement) |
|
181 |
||
182 |
self.unknownBlockBody = (\ |
|
183 |
(Regex("[^\n]+?\s*") + LineEnd().suppress()).setParseAction(self.backend.doStartUnknown) + \ |
|
184 |
ZeroOrMore(self.unknownstatement) \ |
|
185 |
).setParseAction(self.backend.doEndUnknown) |
|
186 |
||
187 |
# Platform |
|
188 |
||
189 |
self.ARMCCBlockStatement = \ |
|
190 |
self.blankline ^ self.preProcessorComment ^ \ |
|
191 |
Line( \ |
|
192 |
CaselessKeyword('ARMRT') ^ \ |
|
193 |
CaselessKeyword('ARMINC') \ |
|
194 |
).setParseAction(self.backend.doSetSwitch) ^ \ |
|
195 |
Line( \ |
|
196 |
(CaselessKeyword('ARMLIBS') + StringList()) \ |
|
197 |
).setParseAction(self.backend.doAppend) |
|
198 |
||
199 |
self.WINSBlockStatement = \ |
|
200 |
self.blankline ^ self.preProcessorComment ^ \ |
|
201 |
Line( \ |
|
202 |
(CaselessKeyword('BASEADDRESS') + HexOrDecNumber()) \ |
|
203 |
).setParseAction(self.backend.doAssignment) ^ \ |
|
204 |
Line( \ |
|
205 |
(CaselessKeyword('WIN32_LIBRARY') + StringList()) \ |
|
206 |
).setParseAction(self.backend.doAppend) ^ \ |
|
207 |
Line( \ |
|
208 |
(CaselessKeyword('WIN32_RESOURCE') + StringList()) \ |
|
209 |
).setParseAction(self.backend.doAppend) ^ \ |
|
210 |
Line( \ |
|
211 |
CaselessKeyword('WIN32_HEADERS') ^ \ |
|
212 |
CaselessKeyword('COPY_FOR_STATIC_LINKAGE') |
|
213 |
).setParseAction(self.backend.doSetSwitch) |
|
214 |
||
215 |
self.TOOLSBlockStatement = \ |
|
216 |
self.blankline ^ self.preProcessorComment ^ \ |
|
217 |
Line( \ |
|
218 |
(CaselessKeyword('WIN32_LIBRARY') + StringList()) \ |
|
219 |
).setParseAction(self.backend.doAppend) |
|
220 |
||
221 |
self.platformBlock = ( \ |
|
222 |
((CaselessKeyword('ARMCC') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) + ZeroOrMore(self.ARMCCBlockStatement)) ^ \ |
|
223 |
((CaselessKeyword('WINS') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) + ZeroOrMore(self.WINSBlockStatement)) ^ \ |
|
224 |
((CaselessKeyword('WINSCW') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) + ZeroOrMore(self.WINSBlockStatement)) ^ \ |
|
225 |
(CaselessKeyword('MARM') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) ^ \ |
|
226 |
((CaselessKeyword('TOOLS') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) + ZeroOrMore(self.TOOLSBlockStatement)) ^ \ |
|
227 |
(CaselessKeyword('WINC') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) + ZeroOrMore(self.WINSBlockStatement) \ |
|
228 |
).setParseAction(self.backend.doEndPlatform) |
|
229 |
||
230 |
# Resource |
|
231 |
||
232 |
self.resourceSetting= \ |
|
233 |
self.blankline ^ self.preProcessorComment ^ \ |
|
234 |
Line( \ |
|
235 |
(CaselessKeyword('TARGET') + String()) ^ \ |
|
236 |
(CaselessKeyword('TARGETPATH') + String()) ^ \ |
|
237 |
(CaselessKeyword('UID') + HexOrDecNumber()) \ |
|
238 |
).setParseAction(self.backend.doResourceAssignment) ^ \ |
|
239 |
Line( \ |
|
240 |
(CaselessKeyword('DEPENDS') + StringList()) ^ \ |
|
241 |
(CaselessKeyword('LANG') + StringList()) \ |
|
242 |
).setParseAction(self.backend.doResourceAppend) ^ \ |
|
243 |
Line( \ |
|
244 |
CaselessKeyword('HEADER') ^ \ |
|
245 |
CaselessKeyword('HEADERONLY') |
|
246 |
).setParseAction(self.backend.doResourceSetSwitch) |
|
247 |
||
248 |
self.resourceBlockBody = (\ |
|
249 |
(CaselessKeyword('RESOURCE') + String() + LineEnd().suppress()).setParseAction(self.backend.doStartResource) \ |
|
250 |
+ ZeroOrMore(self.resourceSetting) \ |
|
251 |
).setParseAction(self.backend.doEndResource) |
|
252 |
||
253 |
# Bitmap |
|
254 |
||
255 |
self.bitmapSetting = \ |
|
256 |
self.blankline ^ self.preProcessorComment ^ \ |
|
257 |
Line( \ |
|
258 |
(CaselessKeyword('TARGETPATH') + String()) \ |
|
259 |
).setParseAction(self.backend.doBitmapAssignment) ^\ |
|
260 |
Line( \ |
|
261 |
(CaselessKeyword('SOURCE') + StringList()) |
|
262 |
).setParseAction(self.backend.doBitmapSourceAssignment) ^\ |
|
263 |
Line( \ |
|
264 |
(CaselessKeyword('SOURCEPATH') + String()) |
|
265 |
).setParseAction(self.backend.doBitmapSourcePathAssignment) ^\ |
|
266 |
Line( \ |
|
267 |
CaselessKeyword('HEADER') |
|
268 |
).setParseAction(self.backend.doBitmapSetSwitch) |
|
269 |
||
270 |
self.bitmapBlockBody = (\ |
|
271 |
(CaselessKeyword('BITMAP') + String() + LineEnd().suppress()).setParseAction(self.backend.doStartBitmap) + \ |
|
272 |
ZeroOrMore(self.bitmapSetting) \ |
|
273 |
).setParseAction(self.backend.doEndBitmap) |
|
274 |
||
275 |
# Stringtable |
|
276 |
||
277 |
self.stringTableSetting = \ |
|
278 |
self.blankline ^ self.preProcessorComment ^ \ |
|
279 |
Line( \ |
|
280 |
(CaselessKeyword('EXPORTPATH') + String()) |
|
281 |
).setParseAction(self.backend.doStringTableAssignment) ^\ |
|
282 |
Line( \ |
|
283 |
CaselessKeyword('HEADERONLY') \ |
|
284 |
).setParseAction(self.backend.doStringTableSetSwitch) |
|
285 |
||
286 |
self.stringTableBlockBody = (\ |
|
287 |
(CaselessKeyword('STRINGTABLE') + String() + LineEnd().suppress()).setParseAction(self.backend.doStartStringTable) + \ |
|
288 |
ZeroOrMore(self.stringTableSetting) \ |
|
289 |
).setParseAction(self.backend.doEndStringTable) |
|
290 |
||
291 |
# Top-level |
|
292 |
self.block = \ |
|
293 |
LineStart() + CaselessLiteral("START") + White().suppress() + \ |
|
294 |
(self.platformBlock ^ self.resourceBlockBody ^ self.bitmapBlockBody ^ self.stringTableBlockBody ^self.unknownBlockBody) + \ |
|
295 |
LineStart() + CaselessLiteral("END") + LineEnd().suppress() |
|
296 |
||
297 |
||
298 |
self.command = \ |
|
299 |
self.assignment ^ self.switch |
|
300 |
||
301 |
# Unknown blocks and statements are ordered i.e. if there's a failure to match something before, |
|
302 |
# then they're "caught" appropriately |
|
303 |
||
304 |
self.mmp = (ZeroOrMore(self.preProcessorComment ^ self.blankline ^ self.block ^ self.command ^ self.unknownstatement)).setParseAction(self.backend.doMMP) |
|
305 |
||
306 |
||
307 |
## MMP Parsing Backends ######################################### |
|
308 |
class MMPBackend(object): |
|
309 |
"""A "backend" for the MMP language |
|
310 |
This may be used to implement a build system, |
|
311 |
source analysis tool or anything else""" |
|
312 |
def __init__(self): |
|
313 |
super(MMPBackend,self).__init__() |
|
314 |
def doPreProcessorComment(self,s,loc,toks): |
|
315 |
return "OK" |
|
316 |
||
317 |
def doStartPlatform(self,s,loc,toks): |
|
318 |
return "OK" |
|
319 |
def doEndPlatform(self,s,loc,toks): |
|
320 |
return "OK" |
|
321 |
||
322 |
def doStartResource(self,s,loc,toks): |
|
323 |
return "OK" |
|
324 |
def doResourceAssignment(self,s,loc,toks): |
|
325 |
return "OK" |
|
326 |
def doResourceAppend(self,s,loc,toks): |
|
327 |
return "OK" |
|
328 |
def doResourceSetSwitch(self,s,loc,toks): |
|
329 |
return "OK" |
|
330 |
def doEndResource(self,s,loc,toks): |
|
331 |
return "OK" |
|
332 |
||
333 |
def doStartBitmap(self,s,loc,toks): |
|
334 |
return "OK" |
|
335 |
def doBitmapAssignment(self,s,loc,toks): |
|
336 |
return "OK" |
|
337 |
def doBitmapSourceAssignment(self,s,loc,toks): |
|
338 |
return "OK" |
|
339 |
def doBitmapSourcePathAssignment(self,s,loc,toks): |
|
340 |
return "OK" |
|
341 |
def doBitmapSetSwitch(self,s,loc,toks): |
|
342 |
return "OK" |
|
343 |
def doEndBitmap(self,s,loc,toks): |
|
344 |
return "OK" |
|
345 |
||
346 |
def doStartStringtable(self,s,loc,toks): |
|
347 |
return "OK" |
|
348 |
def doStringTableAssignment(self,s,loc,toks): |
|
349 |
return "OK" |
|
350 |
def doStringTableSetSwitch(self,s,loc,toks): |
|
351 |
return "OK" |
|
352 |
def doEndStringtable(self,s,loc,toks): |
|
353 |
return "OK" |
|
354 |
||
355 |
def doSetSwitch(self,s,loc,toks): |
|
356 |
return "OK" |
|
357 |
def doAppend(self,s,loc,toks): |
|
358 |
return "OK" |
|
359 |
def doAssignment(self,s,loc,toks): |
|
360 |
return "OK" |
|
361 |
def doUIDAssignment(self,s,loc,toks): |
|
362 |
return "OK" |
|
363 |
def doSourcePathAssignment(self,s,loc,toks): |
|
364 |
return "OK" |
|
365 |
def doSourceAssignment(self,s,loc,toks): |
|
366 |
return "OK" |
|
367 |
||
368 |
def doOldResourceAssignment(self,s,loc,toks): |
|
369 |
return "OK" |
|
370 |
||
371 |
def doUnknownStatement(self,s,loc,toks): |
|
372 |
return "OK" |
|
373 |
def doStartUnknown(self,s,loc,toks): |
|
374 |
return "OK" |
|
375 |
def doEndUnknown(self,s,loc,toks): |
|
376 |
return "OK" |
|
377 |
||
378 |
def doBlankLine(self,s,loc,toks): |
|
379 |
return "OK" |
|
380 |
||
381 |
def doDeprecated(self,s,loc,toks): |
|
382 |
return "OK" |
|
383 |
||
384 |
def doNothing(self): |
|
385 |
return "OK" |
|
386 |
||
387 |
def doMMP(self,s,loc,toks): |
|
388 |
return "MMP" |
|
389 |
||
390 |