Major commit for preparing 1.1.1 release
[spandex:spandex.git] / python / mkactionparser.py
1 #\r
2 # Spandex benchmark and test framework.\r
3 #\r
4 # Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).\r
5 #\r
6 # Contact: Kari J. Kangas <kari.j.kangas@nokia.com>\r
7 #\r
8 #   This framework is free software; you can redistribute it and/or modify it\r
9 # under the terms of the GNU Lesser General Public License as published by the\r
10 # Free Software Foundation, version 2.1 of the License.\r
11 #\r
12 #   This framework is distributed in the hope that it will be useful, but\r
13 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
14 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\r
15 # for more details.\r
16 #\r
17 #   You should have received a copy of the GNU Lesser General Public License\r
18 # along with this framework; if not, see <http://www.gnu.org/licenses/>.\r
19 #\r
20 \r
21 import os, optparse, sys\r
22 from sct import action, formatter\r
23 \r
24 filenameTemplate = 'sct_%smodule_parser.%s'\r
25 WARNING          = '/* NOTE: This file has been generated, you should not edit this file directly */'\r
26 LICENSE          = '''/*\r
27  * Spandex benchmark and test framework.\r
28  *\r
29  * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).\r
30  *\r
31  * Contact: Kari J. Kangas <kari.j.kangas@nokia.com>\r
32  *\r
33  *   This framework is free software; you can redistribute it and/or modify it\r
34  * under the terms of the GNU Lesser General Public License as published by the\r
35  * Free Software Foundation, version 2.1 of the License.\r
36  *\r
37  *   This framework is distributed in the hope that it will be useful, but\r
38  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
39  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License\r
40  * for more details.\r
41  *\r
42  *   You should have received a copy of the GNU Lesser General Public License\r
43  * along with this framework; if not, see <http://www.gnu.org/licenses/>.\r
44  *\r
45  */'''\r
46 \r
47 class ActionParserCFormatter( formatter.CFormatter ):\r
48     def __init__( self, stream ):\r
49         formatter.CFormatter.__init__( self, stream )\r
50         self.localVariables = []\r
51     \r
52     def GenerateError( self, errorMessage ):\r
53         self.StartBlock()\r
54         self.Output( 'SCT_LOG_ERROR( "%s" );' % errorMessage )\r
55         for variable in self.localVariables:\r
56             variable.GenerateDestruction( self )\r
57         self.Output( 'return SCT_FALSE;' )\r
58         self.EndBlock()\r
59 \r
60     def GenerateExternCStart( self ):\r
61         self.Output( '#if defined( __cplusplus )' )\r
62         self.Output( 'extern "C"' )\r
63         self.Output( '{' )\r
64         self.Output( '#endif  /* defined( __cplusplus ) */' )\r
65 \r
66     def GenerateExternCEnd( self ):\r
67         self.Output( '#if defined( __cplusplus )' )\r
68         self.Output( '}' )\r
69         self.Output( '#endif  /* defined( __cplusplus ) */' )\r
70 \r
71     def GenerateActionParser( self, config ):\r
72         self.AddComment( 'Generated parser for %s action in %s module' % (config.type, config.moduleName) )\r
73         self.Output( GetParserFunctionDeclaration( config ) )\r
74         self.StartBlock()\r
75 \r
76         # Gather unique local variables.\r
77         localVariables = {}\r
78         for attrConfig in config.attributeConfigs:\r
79             for variable in attrConfig.localVariables:\r
80                 if variable.name not in localVariables:\r
81                     localVariables[variable.name] = variable\r
82                 else:\r
83                     existingVariable = localVariables[variable.name]\r
84                     assert variable == existingVariable, 'Local variable %s has multiple different definitions.' % variable.name\r
85 \r
86         self.localVariables = localVariables.values()\r
87 \r
88         # Write the local variable definitions.\r
89         for variable in localVariables.values():\r
90             self.Output( variable.definition + ';' )\r
91 \r
92         # Put a newline after the local variable definitions (if any).\r
93         if localVariables:\r
94             self.Output()\r
95 \r
96         self.Output( 'SCT_ASSERT( data != NULL );' )\r
97         self.Output( 'SCT_ASSERT( attributes != NULL );' )\r
98         self.Output( 'SCT_USE_VARIABLE( data );' )\r
99         self.Output( 'SCT_USE_VARIABLE( attributes );' )\r
100         self.Output()\r
101         self.Output( 'if( sctCountListElements( attributes->list ) != %d )' % len( config.attributeConfigs ) )\r
102         self.StartBlock()\r
103         self.Output( 'SCT_LOG_ERROR( "Invalid number of attributes for %s action." );' %\r
104                  config.type );\r
105         self.Output( 'return SCT_FALSE;' )\r
106         self.EndBlock()\r
107         self.Output()\r
108 \r
109         # Generate the local variable initializations.\r
110         for variable in localVariables.values():\r
111             variable.GenerateInitialization( self )\r
112 \r
113         # Generate attribute parsers.\r
114         for cfg in config.attributeConfigs:\r
115             self.AddComment( '%s attribute parsing.' % cfg.name )\r
116             self.GenerateAttributeParser( cfg )\r
117             self.Output()\r
118 \r
119         # Generate code for additional attribute validators (if any).\r
120         if config.validatorConfigs:\r
121             self.AddComment( 'Additional attribute value validation.' )\r
122             for cfg in config.validatorConfigs:\r
123                 self.GenerateValidator( cfg )\r
124             self.Output()\r
125 \r
126         # Generate the local variable destruction code.\r
127         for variable in localVariables.values():\r
128             variable.GenerateDestruction( self )\r
129 \r
130         self.Output( 'return SCT_TRUE;' )\r
131         self.EndBlock()\r
132         self.Output()\r
133 \r
134     def GenerateFunctionDeclaration( self, config ):\r
135         self.AddComment( 'Parser function declaration for %s action' % config.type )\r
136         self.GenerateExternCStart()\r
137         self.Output( GetParserFunctionDeclaration( config ) + ';' )\r
138         self.GenerateExternCEnd()\r
139 \r
140     def GenerateTypes( self, config ):\r
141         self.AddComment( 'Data type definitions for %s action' % config.type )\r
142         for attribConfig in config.attributeConfigs:\r
143             attribConfig.GenerateCType( self )\r
144         self.GenerateStruct( config )\r
145 \r
146     def GenerateStruct( self, config ):\r
147         self.Output( 'typedef struct' )\r
148         self.StartBlock()\r
149         if not config.attributeConfigs:\r
150             # No action attributes, insert a dummy field to satisfy the compiler.\r
151             self.Output( 'int dummy; /* This is a dummy placeholder */' )\r
152         else:\r
153             for attrConfig in config.attributeConfigs:\r
154                 self.Output( attrConfig.GetStructItem() )\r
155         self.EndBlock( ' %s;' % GetStructName( config ) )\r
156 \r
157     def GenerateIncludeGuardStart( self, headerName ):\r
158         define = MakeIncludeGuardDefine( headerName )\r
159         self.Output( '#if !defined( ' + define + ')' )\r
160         self.Output( '#define ' + define )\r
161 \r
162     def GenerateIncludeGuardEnd( self, headerName ):\r
163         define = MakeIncludeGuardDefine( headerName )\r
164         self.Output( '#endif  /* !defined( %s ) */' % define )\r
165 \r
166     def GenerateModuleConfigString( self, moduleName, configData ):\r
167         hexChars   = ['0x%x' % ord( char ) for char in configData]\r
168         # Add a NULL character to the end to create a valid C string.\r
169         hexChars.append( '0x0' )\r
170         arrayInitializer =  '{' + ','.join( hexChars ) + '};'\r
171         self.Output( 'const char _%s_parser_config[] = %s' % (moduleName, arrayInitializer) )\r
172 \r
173     def GenerateActionTemplate( self, config ):\r
174         self.StartBlock( ' "%s",' % config.type )\r
175         for prefix in ['Create', 'Destroy']:\r
176             self.Output( 'scti%s%s%sActionContext,' % (prefix, config.moduleName, config.type) )\r
177         for suffix in ['Init', 'Execute', 'Terminate', 'Destroy', 'GetWorkload']:\r
178             if suffix in config.methods:\r
179                 self.Output( 'scti%s%sAction%s,' % (config.moduleName, config.type, suffix) )\r
180             else:\r
181                 self.Output( 'NULL,' )\r
182         self.EndBlock( ',' )\r
183 \r
184     def GenerateActionTemplateArray( self, actionConfigs ):\r
185         moduleName = actionConfigs[0].moduleName\r
186         self.Output( 'static const SCTActionTemplate %sActionTemplates[] =' % moduleName )\r
187         self.StartBlock()\r
188         for config in actionConfigs:\r
189             self.GenerateActionTemplate( config )\r
190         self.EndBlock( ';' )\r
191 \r
192     def GenerateAttributeParser( self, config ):\r
193         config.GenerateAttributeParser( self )\r
194 \r
195     def GenerateValidator( self, config ):\r
196         config.GenerateC( self )\r
197 \r
198 def GetStructName( config ):\r
199     return '%s%sActionData' % (config.moduleName, config.type)\r
200 \r
201 def GetParserFunctionDeclaration( config ):\r
202     return 'SCTBoolean sctiParse%s%sActionAttributes( %s *data, SCTAttributeList *attributes )' % (config.moduleName, config.type, GetStructName( config ))\r
203 \r
204 def MakeIncludeGuardDefine( headerName ):\r
205     return ('__%s__' % (headerName.replace( '.', '_' ))).upper()\r
206 \r
207 def generateHeader( f ):\r
208     f.Output( LICENSE )\r
209     f.Output()\r
210     f.Output( WARNING )\r
211     f.Output()\r
212 \r
213 def parserGenerator( configPath, sourcePath, headerPath, actionHeaderPath, defines=[] ):\r
214     targetPath           = os.path.dirname( configPath )\r
215     moduleName           = os.path.split( targetPath )[1]\r
216     sourceName           = os.path.split( sourcePath )[1]\r
217     headerName           = os.path.split( headerPath )[1]\r
218     actionHeaderName     = os.path.split( actionHeaderPath )[1]\r
219 \r
220     try:\r
221         parserConfig = action.ProcessModuleConfig( file( configPath ).read(), defines )\r
222     except:\r
223         msg = '! Action config processing failed while parsing %s !' % configPath\r
224         print len( msg ) * '!'\r
225         print msg\r
226         print len( msg ) * '!'\r
227         raise\r
228 \r
229     # Parser source generation.\r
230     f = ActionParserCFormatter( file( sourcePath, 'w' ) )\r
231     generateHeader( f )\r
232     f.Output( '#include "%s"' % headerName )\r
233     f.Output( '#include "string.h"' )\r
234     f.Output( '#include "sct_sicommon.h"' )\r
235     f.Output( '#include "sct_utils.h"' )\r
236     for include in parserConfig.includes:\r
237         f.Output( '#include "%s"' % include )\r
238     f.Output()\r
239     f.GenerateModuleConfigString( moduleName, file( configPath ).read() )\r
240     f.Output()\r
241     for config in parserConfig.actionConfigs:\r
242         f.GenerateActionParser( config )\r
243 \r
244     # Parser header generation.\r
245     f = ActionParserCFormatter( file( headerPath, 'w' ) )\r
246     generateHeader( f )\r
247     f.GenerateIncludeGuardStart( headerName )\r
248     f.Output( '#include "sct_types.h"' )\r
249     for include in parserConfig.includes:\r
250         f.Output( '#include "%s"' % include )\r
251     f.Output( 'extern const char _%s_parser_config[];' % moduleName )\r
252     f.Output()\r
253     for config in parserConfig.actionConfigs:\r
254         f.GenerateTypes( config )\r
255         f.GenerateFunctionDeclaration( config )\r
256         f.Output()\r
257     f.GenerateIncludeGuardEnd( headerName )\r
258 \r
259     # Action template header generation.\r
260     f = ActionParserCFormatter( file( actionHeaderPath, 'w' ) )\r
261     generateHeader( f )\r
262     f.GenerateIncludeGuardStart( actionHeaderName )\r
263     f.Output()\r
264     f.Output( '#include "sct_action.h"' )\r
265     for config in parserConfig.actionConfigs:\r
266         headerName = 'sct_%s%saction.h' % (moduleName, config.type.lower())\r
267         f.Output( '#include "%s"' % headerName )\r
268     f.Output()\r
269     f.GenerateActionTemplateArray( parserConfig.actionConfigs )\r
270     f.GenerateIncludeGuardEnd( actionHeaderName )    \r
271 \r
272 ################################################################################\r
273 # SCons builder\r
274 def moduleGenerator( target, source, env ):\r
275     # Find out the path to the config.py\r
276     configPath       = str( source[0] )\r
277     sourcePath       = str( target[0] )\r
278     headerPath       = str( target[1] )\r
279     actionHeaderPath = str( target[2] )\r
280 \r
281     parserGenerator( configPath, sourcePath, headerPath, actionHeaderPath, env['DEFINES'] )\r
282 \r
283     # Return None to signify success\r
284     return None\r
285 \r
286 ################################################################################\r
287 # Command line interface\r
288 if __name__ == '__main__':\r
289     usage  = 'usage: %prog <config> [<define> [<define> ...]]'\r
290     parser = optparse.OptionParser( usage )\r
291 \r
292     parser.add_option( '--cpp', action='store_true', dest='cpp',\r
293                        default=False, help='create the source file with .cpp extension instead of .c' )\r
294     options, args = parser.parse_args()\r
295 \r
296     # Check arguments.\r
297     if len( args ) < 1:\r
298         parser.error( 'No config file given.' )\r
299 \r
300     # Parse defines.\r
301     defines = {}\r
302     for arg in args[1:]:\r
303         name, value = arg.split( '=', 1 )\r
304         defines[name] = value\r
305         \r
306     configPath = args[0]\r
307     targetPath = os.path.dirname( configPath )\r
308     moduleName = os.path.split( targetPath )[1]\r
309 \r
310     if options.cpp:\r
311         sourceName       = 'sct_%smodule_parser.cpp' % moduleName\r
312     else:\r
313         sourceName       = 'sct_%smodule_parser.c' % moduleName\r
314     headerName           = 'sct_%smodule_parser.h' % moduleName\r
315     actionHeaderName     = 'sct_%smodule_actions.h' % moduleName\r
316 \r
317     sourcePath           = os.path.join( targetPath, sourceName )\r
318     headerPath           = os.path.join( targetPath, headerName )\r
319     actionHeaderPath     = os.path.join( targetPath, actionHeaderName )\r
320     \r
321     parserGenerator( configPath, sourcePath, headerPath, actionHeaderPath, defines )\r