|
1 # |
|
2 # Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
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()) ^ \ |
|
74 Line(CaselessKeyword('ASSPLIBRARY') + StringList()) ^ \ |
|
75 Line(CaselessKeyword('CAPABILITY') + StringList()) ^ \ |
|
76 Line(CaselessKeyword('DOCUMENT') + StringList()) ^ \ |
|
77 Line(CaselessKeyword('EPOCHEAPSIZE') + HexOrDecNumber() + HexOrDecNumber()) ^ \ |
|
78 Line(CaselessKeyword('EPOCPROCESSPRIORITY') + String()) ^ \ |
|
79 Line(CaselessKeyword('FIRSTLIB') + String()) ^ \ |
|
80 Line(CaselessKeyword('TARGET') + String()) ^ \ |
|
81 Line(CaselessKeyword('ROMTARGET') + Optional(StringList())) ^ \ |
|
82 Line(CaselessKeyword('RAMTARGET') + String()) ^ \ |
|
83 Line(CaselessKeyword('TARGETTYPE') + String()) ^ \ |
|
84 Line(CaselessKeyword('TARGETPATH') + String()) ^ \ |
|
85 Line(CaselessKeyword('SYSTEMINCLUDE') + StringList()) ^ \ |
|
86 Line(CaselessKeyword('USERINCLUDE') + StringList()) ^ \ |
|
87 Line(CaselessKeyword('DEFFILE') + String()) ^ \ |
|
88 Line(CaselessKeyword('EXPORTLIBRARY') + String()) ^ \ |
|
89 Line(CaselessKeyword('LINKAS') + String()) ^ \ |
|
90 Line(CaselessKeyword('VENDORID') + HexOrDecNumber()) ^ \ |
|
91 Line(CaselessKeyword('OPTION') + self.toolName + StringList()) ^ \ |
|
92 Line(CaselessKeyword('LINKEROPTION') + self.toolName + StringList()) ^\ |
|
93 Line(CaselessKeyword('OPTION_REPLACE') + self.toolName + StringList()) ^ \ |
|
94 Line(CaselessKeyword('SECUREID') + HexOrDecNumber()) ^ \ |
|
95 Line(CaselessKeyword('EPOCSTACKSIZE') + HexOrDecNumber()) ^ \ |
|
96 Line(CaselessKeyword('VERSION') + String() + Optional(CaselessKeyword('EXPLICIT'))) ^ \ |
|
97 Line(CaselessKeyword('EPOCPROCESSPRIORITY') + String()) ^ \ |
|
98 Line(CaselessKeyword('NEWLIB') + String()) \ |
|
99 ).setParseAction(self.backend.doAssignment) ^ \ |
|
100 ( \ |
|
101 Line(CaselessKeyword('SOURCE') + StringList()).setParseAction(self.backend.doSourceAssignment) \ |
|
102 ).setParseAction(self.backend.doSourceAssignment) ^ \ |
|
103 ( \ |
|
104 Line(CaselessKeyword('RESOURCE') + StringList()).setParseAction(self.backend.doOldResourceAssignment) \ |
|
105 ).setParseAction(self.backend.doOldResourceAssignment) ^ \ |
|
106 ( \ |
|
107 Line(CaselessKeyword('SYSTEMRESOURCE') + StringList()).setParseAction(self.backend.doResourceAssignment) \ |
|
108 ).setParseAction(self.backend.doOldResourceAssignment) ^ \ |
|
109 ( \ |
|
110 Line(CaselessKeyword('SOURCEPATH') + String()).setParseAction(self.backend.doSourceAssignment) \ |
|
111 ).setParseAction(self.backend.doSourcePathAssignment) ^ \ |
|
112 ( \ |
|
113 Line((CaselessKeyword('UID') + Group(HexOrDecNumber() + Optional(HexOrDecNumber())))).setParseAction(self.backend.doUIDAssignment) \ |
|
114 ).setParseAction(self.backend.doUIDAssignment) ^ \ |
|
115 ( \ |
|
116 Line(CaselessKeyword('LANG') + StringList()) \ |
|
117 ).setParseAction(self.backend.doAppend) ^ \ |
|
118 ( \ |
|
119 Line(CaselessKeyword('LIBRARY') + StringList()) \ |
|
120 ).setParseAction(self.backend.doAppend) ^ \ |
|
121 ( \ |
|
122 Line(CaselessKeyword('DEBUGLIBRARY') + StringList()) \ |
|
123 ).setParseAction(self.backend.doAppend) ^ \ |
|
124 ( \ |
|
125 Line(CaselessKeyword('MACRO') + Optional(StringList())) \ |
|
126 ).setParseAction(self.backend.doAppend) ^ \ |
|
127 ( \ |
|
128 Line(CaselessKeyword('AIF') + StringList()) \ |
|
129 ).setParseAction(self.backend.doDeprecated) ^ \ |
|
130 ( \ |
|
131 Line(CaselessKeyword('STATICLIBRARY') + StringList()) \ |
|
132 ).setParseAction(self.backend.doAppend) |
|
133 |
|
134 self.switch = \ |
|
135 (Line( \ |
|
136 CaselessKeyword('ALWAYS_BUILD_AS_ARM') ^ \ |
|
137 CaselessKeyword('ASSPEXPORTS') ^ \ |
|
138 CaselessKeyword('ASSPABI') ^ \ |
|
139 CaselessKeyword('ASSPEXPORTS') ^ \ |
|
140 CaselessKeyword('DEBUGGABLE') ^ \ |
|
141 CaselessKeyword('DEBUGGABLE_UDEBONLY') ^ \ |
|
142 CaselessKeyword('EPOCALLOWDLLDATA') ^ \ |
|
143 CaselessKeyword('EPOCCALLDLLENTRYPOINTS') ^ \ |
|
144 CaselessKeyword('EPOCFIXEDPROCESS') ^ \ |
|
145 CaselessKeyword('EXPORTUNFROZEN') ^ \ |
|
146 CaselessKeyword('FEATUREVARIANT') ^ \ |
|
147 CaselessKeyword('BYTEPAIRCOMPRESSTARGET') ^ \ |
|
148 CaselessKeyword('INFLATECOMPRESSTARGET') ^ \ |
|
149 CaselessKeyword('NOCOMPRESSTARGET') ^ \ |
|
150 CaselessKeyword('NOLINKTIMECODEGENERATION') ^ \ |
|
151 CaselessKeyword('NOMULTIFILECOMPILATION') ^ \ |
|
152 CaselessKeyword('COMPRESSTARGET') ^ \ |
|
153 CaselessKeyword('NOEXPORTLIBRARY') ^ \ |
|
154 CaselessKeyword('NOSTRICTDEF') ^ \ |
|
155 CaselessKeyword('SRCDBG') ^ \ |
|
156 CaselessKeyword('STRICTDEPEND') ^ \ |
|
157 CaselessKeyword('STDCPP') ^ \ |
|
158 CaselessKeyword('NOSTDCPP') ^ \ |
|
159 CaselessKeyword('SMPSAFE') ^ \ |
|
160 CaselessKeyword('PAGED') ^ \ |
|
161 CaselessKeyword('PAGEDCODE') ^ \ |
|
162 CaselessKeyword('PAGEDDATA') ^ \ |
|
163 CaselessKeyword('UNPAGED') ^ \ |
|
164 CaselessKeyword('UNPAGEDCODE') ^ \ |
|
165 CaselessKeyword('UNPAGEDDATA') ^ \ |
|
166 CaselessKeyword('WCHARENTRYPOINT') \ |
|
167 )).setParseAction(self.backend.doSetSwitch) |
|
168 |
|
169 # General |
|
170 |
|
171 self.blankline = (LineStart() + Regex('[\t\r ]*') + LineEnd().suppress() \ |
|
172 ).setParseAction(self.backend.doBlankLine) |
|
173 |
|
174 self.preProcessorComment = (LineStart() + Regex('# .*') + LineEnd().suppress() |
|
175 ).setParseAction(self.backend.doPreProcessorComment) |
|
176 |
|
177 self.unknownstatement = (LineStart() + Regex('.*\S+') + LineEnd().suppress() \ |
|
178 ).setParseAction(self.backend.doUnknownStatement) |
|
179 |
|
180 self.unknownBlockBody = (\ |
|
181 (Regex("[^\n]+?\s*") + LineEnd().suppress()).setParseAction(self.backend.doStartUnknown) + \ |
|
182 ZeroOrMore(self.unknownstatement) \ |
|
183 ).setParseAction(self.backend.doEndUnknown) |
|
184 |
|
185 # Platform |
|
186 |
|
187 self.ARMCCBlockStatement = \ |
|
188 self.blankline ^ self.preProcessorComment ^ \ |
|
189 Line( \ |
|
190 CaselessKeyword('ARMRT') ^ \ |
|
191 CaselessKeyword('ARMINC') \ |
|
192 ).setParseAction(self.backend.doSetSwitch) ^ \ |
|
193 Line( \ |
|
194 (CaselessKeyword('ARMLIBS') + StringList()) \ |
|
195 ).setParseAction(self.backend.doAppend) |
|
196 |
|
197 self.WINSBlockStatement = \ |
|
198 self.blankline ^ self.preProcessorComment ^ \ |
|
199 Line( \ |
|
200 (CaselessKeyword('BASEADDRESS') + HexOrDecNumber()) \ |
|
201 ).setParseAction(self.backend.doAssignment) ^ \ |
|
202 Line( \ |
|
203 (CaselessKeyword('WIN32_LIBRARY') + StringList()) \ |
|
204 ).setParseAction(self.backend.doAppend) ^ \ |
|
205 Line( \ |
|
206 (CaselessKeyword('WIN32_RESOURCE') + StringList()) \ |
|
207 ).setParseAction(self.backend.doAppend) ^ \ |
|
208 Line( \ |
|
209 CaselessKeyword('WIN32_HEADERS') ^ \ |
|
210 CaselessKeyword('COPY_FOR_STATIC_LINKAGE') |
|
211 ).setParseAction(self.backend.doSetSwitch) |
|
212 |
|
213 self.TOOLSBlockStatement = \ |
|
214 self.blankline ^ self.preProcessorComment ^ \ |
|
215 Line( \ |
|
216 (CaselessKeyword('WIN32_LIBRARY') + StringList()) \ |
|
217 ).setParseAction(self.backend.doAppend) |
|
218 |
|
219 self.platformBlock = ( \ |
|
220 ((CaselessKeyword('ARMCC') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) + ZeroOrMore(self.ARMCCBlockStatement)) ^ \ |
|
221 ((CaselessKeyword('WINS') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) + ZeroOrMore(self.WINSBlockStatement)) ^ \ |
|
222 ((CaselessKeyword('WINSCW') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) + ZeroOrMore(self.WINSBlockStatement)) ^ \ |
|
223 (CaselessKeyword('MARM') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) ^ \ |
|
224 ((CaselessKeyword('TOOLS') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) + ZeroOrMore(self.TOOLSBlockStatement)) ^ \ |
|
225 (CaselessKeyword('WINC') + LineEnd().suppress()).setParseAction(self.backend.doStartPlatform) + ZeroOrMore(self.WINSBlockStatement) \ |
|
226 ).setParseAction(self.backend.doEndPlatform) |
|
227 |
|
228 # Resource |
|
229 |
|
230 self.resourceSetting= \ |
|
231 self.blankline ^ self.preProcessorComment ^ \ |
|
232 Line( \ |
|
233 (CaselessKeyword('TARGET') + String()) ^ \ |
|
234 (CaselessKeyword('TARGETPATH') + String()) ^ \ |
|
235 (CaselessKeyword('UID') + HexOrDecNumber()) \ |
|
236 ).setParseAction(self.backend.doResourceAssignment) ^ \ |
|
237 Line( \ |
|
238 (CaselessKeyword('DEPENDS') + StringList()) ^ \ |
|
239 (CaselessKeyword('LANG') + StringList()) \ |
|
240 ).setParseAction(self.backend.doResourceAppend) ^ \ |
|
241 Line( \ |
|
242 CaselessKeyword('HEADER') ^ \ |
|
243 CaselessKeyword('HEADERONLY') |
|
244 ).setParseAction(self.backend.doResourceSetSwitch) |
|
245 |
|
246 self.resourceBlockBody = (\ |
|
247 (CaselessKeyword('RESOURCE') + String() + LineEnd().suppress()).setParseAction(self.backend.doStartResource) \ |
|
248 + ZeroOrMore(self.resourceSetting) \ |
|
249 ).setParseAction(self.backend.doEndResource) |
|
250 |
|
251 # Bitmap |
|
252 |
|
253 self.bitmapSetting = \ |
|
254 self.blankline ^ self.preProcessorComment ^ \ |
|
255 Line( \ |
|
256 (CaselessKeyword('TARGETPATH') + String()) \ |
|
257 ).setParseAction(self.backend.doBitmapAssignment) ^\ |
|
258 Line( \ |
|
259 (CaselessKeyword('SOURCE') + StringList()) |
|
260 ).setParseAction(self.backend.doBitmapSourceAssignment) ^\ |
|
261 Line( \ |
|
262 (CaselessKeyword('SOURCEPATH') + String()) |
|
263 ).setParseAction(self.backend.doBitmapSourcePathAssignment) ^\ |
|
264 Line( \ |
|
265 CaselessKeyword('HEADER') |
|
266 ).setParseAction(self.backend.doBitmapSetSwitch) |
|
267 |
|
268 self.bitmapBlockBody = (\ |
|
269 (CaselessKeyword('BITMAP') + String() + LineEnd().suppress()).setParseAction(self.backend.doStartBitmap) + \ |
|
270 ZeroOrMore(self.bitmapSetting) \ |
|
271 ).setParseAction(self.backend.doEndBitmap) |
|
272 |
|
273 # Stringtable |
|
274 |
|
275 self.stringTableSetting = \ |
|
276 self.blankline ^ self.preProcessorComment ^ \ |
|
277 Line( \ |
|
278 (CaselessKeyword('EXPORTPATH') + String()) |
|
279 ).setParseAction(self.backend.doStringTableAssignment) ^\ |
|
280 Line( \ |
|
281 CaselessKeyword('HEADERONLY') \ |
|
282 ).setParseAction(self.backend.doStringTableSetSwitch) |
|
283 |
|
284 self.stringTableBlockBody = (\ |
|
285 (CaselessKeyword('STRINGTABLE') + String() + LineEnd().suppress()).setParseAction(self.backend.doStartStringTable) + \ |
|
286 ZeroOrMore(self.stringTableSetting) \ |
|
287 ).setParseAction(self.backend.doEndStringTable) |
|
288 |
|
289 # Top-level |
|
290 self.block = \ |
|
291 LineStart() + CaselessLiteral("START") + White().suppress() + \ |
|
292 (self.platformBlock ^ self.resourceBlockBody ^ self.bitmapBlockBody ^ self.stringTableBlockBody ^self.unknownBlockBody) + \ |
|
293 LineStart() + CaselessLiteral("END") + LineEnd().suppress() |
|
294 |
|
295 |
|
296 self.command = \ |
|
297 self.assignment ^ self.switch |
|
298 |
|
299 # Unknown blocks and statements are ordered i.e. if there's a failure to match something before, |
|
300 # then they're "caught" appropriately |
|
301 |
|
302 self.mmp = (ZeroOrMore(self.preProcessorComment ^ self.blankline ^ self.block ^ self.command ^ self.unknownstatement)).setParseAction(self.backend.doMMP) |
|
303 |
|
304 |
|
305 ## MMP Parsing Backends ######################################### |
|
306 class MMPBackend(object): |
|
307 """A "backend" for the MMP language |
|
308 This may be used to implement a build system, |
|
309 source analysis tool or anything else""" |
|
310 def __init__(self): |
|
311 super(MMPBackend,self).__init__() |
|
312 def doPreProcessorComment(self,s,loc,toks): |
|
313 return "OK" |
|
314 |
|
315 def doStartPlatform(self,s,loc,toks): |
|
316 return "OK" |
|
317 def doEndPlatform(self,s,loc,toks): |
|
318 return "OK" |
|
319 |
|
320 def doStartResource(self,s,loc,toks): |
|
321 return "OK" |
|
322 def doResourceAssignment(self,s,loc,toks): |
|
323 return "OK" |
|
324 def doResourceAppend(self,s,loc,toks): |
|
325 return "OK" |
|
326 def doResourceSetSwitch(self,s,loc,toks): |
|
327 return "OK" |
|
328 def doEndResource(self,s,loc,toks): |
|
329 return "OK" |
|
330 |
|
331 def doStartBitmap(self,s,loc,toks): |
|
332 return "OK" |
|
333 def doBitmapAssignment(self,s,loc,toks): |
|
334 return "OK" |
|
335 def doBitmapSourceAssignment(self,s,loc,toks): |
|
336 return "OK" |
|
337 def doBitmapSourcePathAssignment(self,s,loc,toks): |
|
338 return "OK" |
|
339 def doBitmapSetSwitch(self,s,loc,toks): |
|
340 return "OK" |
|
341 def doEndBitmap(self,s,loc,toks): |
|
342 return "OK" |
|
343 |
|
344 def doStartStringtable(self,s,loc,toks): |
|
345 return "OK" |
|
346 def doStringTableAssignment(self,s,loc,toks): |
|
347 return "OK" |
|
348 def doStringTableSetSwitch(self,s,loc,toks): |
|
349 return "OK" |
|
350 def doEndStringtable(self,s,loc,toks): |
|
351 return "OK" |
|
352 |
|
353 def doSetSwitch(self,s,loc,toks): |
|
354 return "OK" |
|
355 def doAppend(self,s,loc,toks): |
|
356 return "OK" |
|
357 def doAssignment(self,s,loc,toks): |
|
358 return "OK" |
|
359 def doUIDAssignment(self,s,loc,toks): |
|
360 return "OK" |
|
361 def doSourcePathAssignment(self,s,loc,toks): |
|
362 return "OK" |
|
363 def doSourceAssignment(self,s,loc,toks): |
|
364 return "OK" |
|
365 |
|
366 def doOldResourceAssignment(self,s,loc,toks): |
|
367 return "OK" |
|
368 |
|
369 def doUnknownStatement(self,s,loc,toks): |
|
370 return "OK" |
|
371 def doStartUnknown(self,s,loc,toks): |
|
372 return "OK" |
|
373 def doEndUnknown(self,s,loc,toks): |
|
374 return "OK" |
|
375 |
|
376 def doBlankLine(self,s,loc,toks): |
|
377 return "OK" |
|
378 |
|
379 def doDeprecated(self,s,loc,toks): |
|
380 return "OK" |
|
381 |
|
382 def doNothing(self): |
|
383 return "OK" |
|
384 |
|
385 def doMMP(self,s,loc,toks): |
|
386 return "MMP" |
|
387 |
|
388 |