3 parser.c: Generate helper declarations and functions to trace events
4 from an event description file.
6 Copyright (C) 2002, Xianxiu Yang
7 Copyright (C) 2002, Michel Dagenais
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; version 2 of the License.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /* This program reads the ".event" event definitions input files
23 specified as command line arguments and generates corresponding
24 ".c" and ".h" files required to trace such events in the kernel.
26 The program uses a very simple tokenizer, called from a hand written
27 recursive descent parser to fill a data structure describing the events.
28 The result is a sequence of events definitions which refer to type
31 A table of named types is maintained to allow refering to types by name
32 when the same type is used at several places. Finally a sequence of
33 all types is maintained to facilitate the freeing of all type
34 information when the processing of an ".event" file is finished. */
40 #include <linux/errno.h>
46 /*****************************************************************************
48 * getSize : translate from string to integer
50 * in : input file handle
53 *****************************************************************************/
54 int getSize(parse_file
*in
){
58 if(in
->type
== NUMBER
) {
59 if(strcmp(token
,"1") == 0) return 0;
60 else if(strcmp(token
,"2") == 0) return 1;
61 else if(strcmp(token
,"4") == 0) return 2;
62 else if(strcmp(token
,"8") == 0) return 3;
64 else if(in
->type
== NAME
) {
65 if(strcmp(token
,"short") == 0) return 4;
66 else if(strcmp(token
,"medium") == 0) return 5;
67 else if(strcmp(token
,"long") == 0) return 6;
69 in
->error(in
,"incorrect size specification");
73 /*****************************************************************************
75 * error_callback : print out error info
77 * in : input file handle
78 * msg : message to be printed
79 ****************************************************************************/
80 void error_callback(parse_file
*in
, char *msg
){
82 printf("Error in file %s, line %d: %s\n", in
->name
, in
->lineno
, msg
);
88 /*****************************************************************************
90 * memAlloc : allocate memory
92 * size : required memory size
94 * void * : pointer to allocate memory or NULL
95 ****************************************************************************/
96 void * memAlloc(int size
){
97 void *addr
= malloc(size
);
99 printf("Failed to allocate memory");
105 /*****************************************************************************
107 * allocAndCopy : allocate memory and initialize it
109 * str : string to be put in memory
111 * char * : pointer to allocate memory or NULL
112 ****************************************************************************/
113 char *allocAndCopy(char *str
){
114 char *addr
= (char *)memAlloc(strlen(str
)+1);
120 /*****************************************************************************
122 * parseEvent : generate event from event definition
124 * in : input file handle
127 * ev : new event (parameters are passed to it)
128 ****************************************************************************/
129 void parseEvent(parse_file
*in
, event
* ev
, sequence
* unnamed_types
, table
* named_types
) {
135 ev
->name
= allocAndCopy(token
);
138 token
= getQuotedString(in
);
139 ev
->description
= allocAndCopy(token
);
141 token
= getToken(in
); //token either is a ',' or a ')'
142 if(in
->type
== COMA
) token
= getName(in
);
145 /* We have a possibly empty list of fields, containing struct implied */
146 if((in
->type
== NAME
&& strcmp(token
,"field") == 0) ||
147 in
->type
== RPARENTHESIS
) {
148 /* Insert an unnamed struct type */
149 t
= (type_descriptor
*)memAlloc(sizeof(type_descriptor
));
152 if(in
->type
== NAME
) parseFields(in
,t
, unnamed_types
, named_types
);
153 else if(in
->type
== RPARENTHESIS
) sequence_init(&(t
->fields
));
154 sequence_push(unnamed_types
,t
);
158 /* Or a complete type declaration but it must be a struct */
159 else if(in
->type
== NAME
){
160 ev
->type
= parseType(in
,NULL
, unnamed_types
, named_types
);
161 if(ev
->type
->type
!= STRUCT
&& ev
->type
->type
!= NONE
) in
->error(in
,"type must be a struct");
162 }else in
->error(in
,"not a struct type");
168 /*****************************************************************************
170 * parseField : get field infomation from buffer
172 * in : input file handle
173 * t : type descriptor
174 ****************************************************************************/
175 void parseFields(parse_file
*in
, type_descriptor
*t
, sequence
* unnamed_types
, table
* named_types
) {
179 sequence_init(&(t
->fields
));
181 token
= getToken(in
);
182 while(in
->type
== NAME
&& strcmp(token
,"field") == 0) {
183 f
= (field
*)memAlloc(sizeof(field
));
184 sequence_push(&(t
->fields
),f
);
187 f
->name
= (char *)allocAndCopy(getName(in
));
189 f
->description
= (char *)allocAndCopy(getQuotedString(in
));
191 f
->type
= parseType(in
,NULL
, unnamed_types
, named_types
);
194 token
= getToken(in
);
195 if(in
->type
== COMA
) token
= getName(in
);
196 else ungetToken(in
); // no more fields, it must be a ')'
199 if(in
->type
== NAME
&& strcmp(token
,"field") != 0)
200 in
->error(in
,"not a field");
204 /*****************************************************************************
206 * parseType : get type information, type can be :
208 * int(size,fmt); uint(size,fmt); float(size,fmt);
209 * string(fmt); enum(size,fmt,(label1,label2...))
211 * array(arraySize, type); sequence(lengthSize,type)
212 * struct(field(name,type,description)...)
216 * in : input file handle
217 * inType : a type descriptor
219 * type_descriptor* : a type descriptor
220 ****************************************************************************/
221 type_descriptor
*parseType(parse_file
*in
, type_descriptor
*inType
, sequence
* unnamed_types
, table
* named_types
) {
226 t
= (type_descriptor
*) memAlloc(sizeof(type_descriptor
));
229 sequence_push(unnamed_types
,t
);
235 if(strcmp(token
,"struct") == 0) {
238 parseFields(in
,t
, unnamed_types
, named_types
);
241 else if(strcmp(token
,"array") == 0) {
244 t
->size
= getNumber(in
);
246 t
->nested_type
= parseType(in
,NULL
, unnamed_types
, named_types
);
249 else if(strcmp(token
,"sequence") == 0) {
252 t
->size
= getSize(in
);
254 t
->nested_type
= parseType(in
,NULL
, unnamed_types
, named_types
);
257 else if(strcmp(token
,"enum") == 0) {
259 sequence_init(&(t
->labels
));
261 t
->size
= getSize(in
);
263 token
= getToken(in
);
264 if(in
->type
== QUOTEDSTRING
){
265 t
->fmt
= allocAndCopy(token
);
267 }else ungetToken(in
);
270 token
= getToken(in
);
271 while(in
->type
!= RPARENTHESIS
) {
272 if(in
->type
!= NAME
) in
->error(in
,"Name token was expected");
273 car
= allocAndCopy(token
);
274 token
= getToken(in
);
275 if(in
->type
== COMA
){
276 sequence_push(&(t
->labels
),allocAndCopy(car
));
278 }else if(in
->type
== EQUAL
){ //label followed by '=' and a number, e.x. label1 = 1,
279 car
= appendString(car
, token
);
280 token
= getToken(in
);
281 if(in
->type
!= NUMBER
) in
->error(in
,"Number token was expected");
282 car
= appendString(car
, token
);
283 sequence_push(&(t
->labels
),allocAndCopy(car
));
284 token
= getToken(in
);
285 if(in
->type
== COMA
) token
= getName(in
);
288 sequence_push(&(t
->labels
),allocAndCopy(car
));
295 else if(strcmp(token
,"int") == 0) {
298 t
->size
= getSize(in
);
299 token
= getToken(in
);
300 if(in
->type
== COMA
) {
301 token
= getQuotedString(in
);
302 t
->fmt
= allocAndCopy(token
);
307 else if(strcmp(token
,"uint") == 0) {
310 t
->size
= getSize(in
);
311 token
= getToken(in
);
312 if(in
->type
== COMA
) {
313 token
= getQuotedString(in
);
314 t
->fmt
= allocAndCopy(token
);
319 else if(strcmp(token
,"float") == 0) {
322 t
->size
= getSize(in
);
323 token
= getToken(in
);
324 if(in
->type
== COMA
) {
325 token
= getQuotedString(in
);
326 t
->fmt
= allocAndCopy(token
);
331 else if(strcmp(token
,"string") == 0) {
334 token
= getToken(in
);
335 if(in
->type
== QUOTEDSTRING
) t
->fmt
= allocAndCopy(token
);
340 /* Must be a named type */
342 in
->error(in
,"Named type cannot refer to a named type");
345 sequence_pop(unnamed_types
);
346 return(find_named_type(token
, named_types
));
353 /*****************************************************************************
355 * find_named_type : find a named type from hash table
359 * type_descriptor * : a type descriptor
360 *****************************************************************************/
362 type_descriptor
* find_named_type(char *name
, table
* named_types
)
366 t
= table_find(named_types
,name
);
368 t
= (type_descriptor
*)memAlloc(sizeof(type_descriptor
));
371 table_insert(named_types
,allocAndCopy(name
),t
);
376 /*****************************************************************************
378 * parseTypeDefinition : get type information from type definition
380 * in : input file handle
381 *****************************************************************************/
382 void parseTypeDefinition(parse_file
* in
, sequence
* unnamed_types
, table
* named_types
){
388 t
= find_named_type(token
, named_types
);
391 if(t
->type
!= NONE
) in
->error(in
,"redefinition of named type");
392 parseType(in
,t
, unnamed_types
, named_types
);
398 /**************************************************************************
400 * getComa, getName, getNumber, getLParenthesis, getRParenthesis, getEqual
402 * Read a token from the input file, check its type, return it scontent.
405 * in , input file handle.
408 * address of token content.
410 **************************************************************************/
412 char *getName(parse_file
* in
) {
415 token
= getToken(in
);
416 if(in
->type
!= NAME
) in
->error(in
,"Name token was expected");
420 int getNumber(parse_file
* in
) {
423 token
= getToken(in
);
424 if(in
->type
!= NUMBER
) in
->error(in
, "Number token was expected");
428 char *getComa(parse_file
* in
) {
431 token
= getToken(in
);
432 if(in
->type
!= COMA
) in
->error(in
, "Coma token was expected");
436 char *getLParenthesis(parse_file
* in
) {
439 token
= getToken(in
);
440 if(in
->type
!= LPARENTHESIS
) in
->error(in
, "Left parenthesis was expected");
444 char *getRParenthesis(parse_file
* in
) {
447 token
= getToken(in
);
448 if(in
->type
!= RPARENTHESIS
) in
->error(in
, "Right parenthesis was expected");
452 char *getQuotedString(parse_file
* in
) {
455 token
= getToken(in
);
456 if(in
->type
!= QUOTEDSTRING
) in
->error(in
, "quoted string was expected");
460 char * getSemiColon(parse_file
*in
){
463 token
= getToken(in
);
464 if(in
->type
!= SEMICOLON
) in
->error(in
, "semicolon was expected");
468 char * getEqual(parse_file
*in
){
471 token
= getToken(in
);
472 if(in
->type
!= EQUAL
) in
->error(in
, "equal was expected");
476 /******************************************************************
478 * getToken, ungetToken
480 * Read a token from the input file and return its type and content.
481 * Line numbers are accounted for and whitespace/comments are skipped.
484 * in, input file handle.
487 * address of token content.
489 ******************************************************************/
491 void ungetToken(parse_file
* in
)
496 char *getToken(parse_file
* in
)
500 int pos
= 0, escaped
;
507 /* skip whitespace and comments */
509 while((car
= getc(fp
)) != EOF
) {
512 if(car1
== '*') skipComment(in
);
513 else if(car1
== '/') skipEOL(in
);
515 car1
= ungetc(car1
,fp
);
519 else if(car
== '\n') in
->lineno
++;
520 else if(!isspace(car
)) break;
529 in
->buffer
[pos
] = car
;
533 in
->type
= LPARENTHESIS
;
534 in
->buffer
[pos
] = car
;
538 in
->type
= RPARENTHESIS
;
539 in
->buffer
[pos
] = car
;
543 in
->type
= SEMICOLON
;
544 in
->buffer
[pos
] = car
;
549 in
->buffer
[pos
] = car
;
554 while((car
= getc(fp
)) != EOF
&& pos
< BUFFER_SIZE
) {
555 if(car
== '\\' && escaped
== 0) {
556 in
->buffer
[pos
] = car
;
561 if(car
== '"' && escaped
== 0) break;
562 if(car
== '\n' && escaped
== 0) {
563 in
->error(in
, "non escaped newline inside quoted string");
565 if(car
== '\n') in
->lineno
++;
566 in
->buffer
[pos
] = car
;
570 if(car
== EOF
) in
->error(in
,"no ending quotemark");
571 if(pos
== BUFFER_SIZE
) in
->error(in
, "quoted string token too large");
572 in
->type
= QUOTEDSTRING
;
576 in
->buffer
[pos
] = car
;
578 while((car
= getc(fp
)) != EOF
&& pos
< BUFFER_SIZE
) {
583 in
->buffer
[pos
] = car
;
586 if(car
== EOF
) ungetc(car
,fp
);
587 if(pos
== BUFFER_SIZE
) in
->error(in
, "number token too large");
590 else if(isalpha(car
)) {
593 while((car
= getc(fp
)) != EOF
&& pos
< BUFFER_SIZE
) {
598 in
->buffer
[pos
] = car
;
601 if(car
== EOF
) ungetc(car
,fp
);
602 if(pos
== BUFFER_SIZE
) in
->error(in
, "name token too large");
605 else in
->error(in
, "invalid character, unrecognized token");
611 void skipComment(parse_file
* in
)
614 while((car
= getc(in
->fp
)) != EOF
) {
615 if(car
== '\n') in
->lineno
++;
616 else if(car
== '*') {
619 if(car
== '/') return;
623 if(car
== EOF
) in
->error(in
,"comment begining with '/*' has no ending '*/'");
626 void skipEOL(parse_file
* in
)
629 while((car
= getc(in
->fp
)) != EOF
) {
635 if(car
== EOF
)ungetc(car
, in
->fp
);
640 if(c
== '_')return 1;
643 if((i
>=0 && i
<26) || (j
>=0 && j
<26)) return 1;
648 return (isalpha(c
) || isdigit(c
));
651 /*****************************************************************************
653 * checkNamedTypesImplemented : check if all named types have definition
654 ****************************************************************************/
655 void checkNamedTypesImplemented(table
* named_types
){
660 for(pos
= 0 ; pos
< named_types
->values
.position
; pos
++) {
661 t
= (type_descriptor
*) named_types
->values
.array
[pos
];
663 sprintf(str
,"named type '%s' has no definition",(char*)named_types
->keys
.array
[pos
]);
664 error_callback(NULL
,str
);
670 /*****************************************************************************
672 * generateChecksum : generate checksum for the facility
674 * facName : name of facility
676 * checksum : checksum for the facility
677 ****************************************************************************/
678 void generateChecksum( char* facName
, unsigned long * checksum
, sequence
* events
){
680 int pos
, nestedStruct
;
684 crc
= crc32(facName
);
685 for(pos
= 0; pos
< events
->position
; pos
++){
686 ev
= (event
*)(events
->array
[pos
]);
687 ev
->nested
= 0; //by default, event has no nested struct
688 crc
= partial_crc32(ev
->name
,crc
);
690 if(ev
->type
->type
!= STRUCT
){
691 sprintf(str
,"event '%s' has a type other than STRUCT",ev
->name
);
692 error_callback(NULL
, str
);
694 crc
= getTypeChecksum(crc
, ev
->type
,&nestedStruct
);
695 if(nestedStruct
) ev
->nested
= 1;
700 /*****************************************************************************
702 * getTypeChecksum : generate checksum by type info
704 * crc : checksum generated so far
705 * type : type descriptor containing type info
707 * unsigned long : checksum
708 *****************************************************************************/
709 unsigned long getTypeChecksum(unsigned long aCrc
, type_descriptor
* type
, int * nestedStruct
){
710 unsigned long crc
= aCrc
;
711 char * str
= NULL
, buf
[16];
712 int flag
= 0, pos
, max
, min
;
718 str
= intOutputTypes
[type
->size
];
721 str
= uintOutputTypes
[type
->size
];
724 str
= floatOutputTypes
[type
->size
];
727 str
= allocAndCopy("string");
731 str
= appendString("enum ", uintOutputTypes
[type
->size
]);
735 sprintf(buf
,"%d\0",type
->size
);
736 str
= appendString("array ",buf
);
740 sprintf(buf
,"%d\0",type
->size
);
741 str
= appendString("sequence ",buf
);
745 str
= allocAndCopy("struct");
749 error_callback(NULL
, "named type has no definition");
753 crc
= partial_crc32(str
,crc
);
756 if(type
->fmt
) crc
= partial_crc32(type
->fmt
,crc
);
758 if(type
->type
== ARRAY
|| type
->type
== SEQUENCE
){
759 dt
= type
->nested_type
->type
;
760 if(dt
== ARRAY
|| dt
== SEQUENCE
|| dt
== STRUCT
) *nestedStruct
+= 1;
761 crc
= getTypeChecksum(crc
,type
->nested_type
,nestedStruct
);
762 }else if(type
->type
== STRUCT
){
763 if(type
->fields
.position
!= 0){//not a empty struct
765 for(pos
=0; pos
< type
->fields
.position
; pos
++){
767 fld
= (field
*) type
->fields
.array
[pos
];
768 crc
= partial_crc32(fld
->name
,crc
);
769 if(fld
->type
->type
== STRUCT
) min
++;
770 crc
= getTypeChecksum(crc
, fld
->type
,&min
);
771 if(min
>max
) max
= min
;
773 *nestedStruct
+= max
;
775 }else if(type
->type
== ENUM
){
776 for(pos
= 0; pos
< type
->labels
.position
; pos
++)
777 crc
= partial_crc32((char*)type
->labels
.array
[pos
],crc
);
784 /* Event type descriptors */
785 void freeType(type_descriptor
* tp
){
789 if(tp
->fmt
!= NULL
) free(tp
->fmt
);
790 if(tp
->type
== ENUM
) {
791 for(pos2
= 0; pos2
< tp
->labels
.position
; pos2
++) {
792 free(tp
->labels
.array
[pos2
]);
794 sequence_dispose(&(tp
->labels
));
796 if(tp
->type
== STRUCT
) {
797 for(pos2
= 0; pos2
< tp
->fields
.position
; pos2
++) {
798 f
= (field
*) tp
->fields
.array
[pos2
];
800 free(f
->description
);
803 sequence_dispose(&(tp
->fields
));
807 void freeNamedType(table
* t
){
809 type_descriptor
* td
;
811 for(pos
= 0 ; pos
< t
->keys
.position
; pos
++) {
812 free((char *)t
->keys
.array
[pos
]);
813 td
= (type_descriptor
*)t
->values
.array
[pos
];
819 void freeTypes(sequence
*t
) {
824 for(pos
= 0 ; pos
< t
->position
; pos
++) {
825 tp
= (type_descriptor
*)t
->array
[pos
];
831 void freeEvents(sequence
*t
) {
835 for(pos
= 0 ; pos
< t
->position
; pos
++) {
836 ev
= (event
*) t
->array
[pos
];
838 free(ev
->description
);
845 /* Extensible array */
847 void sequence_init(sequence
*t
) {
850 t
->array
= (void **)memAlloc(t
->size
* sizeof(void *));
853 void sequence_dispose(sequence
*t
) {
859 void sequence_push(sequence
*t
, void *elem
) {
862 if(t
->position
>= t
->size
) {
864 t
->array
= (void **)memAlloc(t
->size
* 2 * sizeof(void *));
865 memcpy(t
->array
, tmp
, t
->size
* sizeof(void *));
866 t
->size
= t
->size
* 2;
869 t
->array
[t
->position
] = elem
;
873 void *sequence_pop(sequence
*t
) {
874 return t
->array
[t
->position
--];
878 /* Hash table API, implementation is just linear search for now */
880 void table_init(table
*t
) {
881 sequence_init(&(t
->keys
));
882 sequence_init(&(t
->values
));
885 void table_dispose(table
*t
) {
886 sequence_dispose(&(t
->keys
));
887 sequence_dispose(&(t
->values
));
890 void table_insert(table
*t
, char *key
, void *value
) {
891 sequence_push(&(t
->keys
),key
);
892 sequence_push(&(t
->values
),value
);
895 void *table_find(table
*t
, char *key
) {
897 for(pos
= 0 ; pos
< t
->keys
.position
; pos
++) {
898 if(strcmp((char *)key
,(char *)t
->keys
.array
[pos
]) == 0)
899 return(t
->values
.array
[pos
]);
905 /* Concatenate strings */
907 char *appendString(char *s
, char *suffix
) {
910 tmp
= (char *)memAlloc(strlen(s
) + strlen(suffix
) + 1);
This page took 0.048094 seconds and 4 git commands to generate.