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 *****************************************************************************/
55 int getSize(parse_file
*in
)
60 if(in
->type
== NUMBER
) {
61 if(strcmp(token
,"1") == 0) return 0;
62 else if(strcmp(token
,"2") == 0) return 1;
63 else if(strcmp(token
,"4") == 0) return 2;
64 else if(strcmp(token
,"8") == 0) return 3;
66 else if(in
->type
== NAME
) {
67 if(strcmp(token
,"short") == 0) return 4;
68 else if(strcmp(token
,"medium") == 0) return 5;
69 else if(strcmp(token
,"long") == 0) return 6;
71 in
->error(in
,"incorrect size specification");
75 /*****************************************************************************
77 * error_callback : print out error info
79 * in : input file handle
80 * msg : message to be printed
81 ****************************************************************************/
83 void error_callback(parse_file
*in
, char *msg
)
86 printf("Error in file %s, line %d: %s\n", in
->name
, in
->lineno
, msg
);
92 /*****************************************************************************
94 * memAlloc : allocate memory
96 * size : required memory size
98 * void * : pointer to allocate memory or NULL
99 ****************************************************************************/
101 void * memAlloc(int size
)
103 void *addr
= malloc(size
);
105 printf("Failed to allocate memory");
111 /*****************************************************************************
113 * allocAndCopy : allocate memory and initialize it
115 * str : string to be put in memory
117 * char * : pointer to allocate memory or NULL
118 ****************************************************************************/
120 char *allocAndCopy(char *str
)
122 char *addr
= (char *)memAlloc(strlen(str
)+1);
128 /*****************************************************************************
130 * parseEvent : generate event from event definition
132 * in : input file handle
135 * ev : new event (parameters are passed to it)
136 ****************************************************************************/
138 void parseEvent(parse_file
*in
, event
* ev
, sequence
* unnamed_types
,
146 ev
->name
= allocAndCopy(token
);
149 token
= getQuotedString(in
);
150 ev
->description
= allocAndCopy(token
);
152 token
= getToken(in
); //token either is a ',' or a ')'
153 if(in
->type
== COMA
) token
= getName(in
);
156 /* We have a possibly empty list of fields, containing struct implied */
157 if((in
->type
== NAME
&& strcmp(token
,"field") == 0) ||
158 in
->type
== RPARENTHESIS
) {
159 /* Insert an unnamed struct type */
160 t
= (type_descriptor
*)memAlloc(sizeof(type_descriptor
));
164 if(in
->type
== NAME
) parseFields(in
,t
, unnamed_types
, named_types
);
165 else if(in
->type
== RPARENTHESIS
) sequence_init(&(t
->fields
));
166 sequence_push(unnamed_types
,t
);
170 /* Or a complete type declaration but it must be a struct */
171 else if(in
->type
== NAME
){
172 ev
->type
= parseType(in
,NULL
, unnamed_types
, named_types
);
173 if(ev
->type
->type
!= STRUCT
&& ev
->type
->type
!= NONE
) in
->error(in
,"type must be a struct");
174 }else in
->error(in
,"not a struct type");
180 /*****************************************************************************
182 * parseField : get field infomation from buffer
184 * in : input file handle
185 * t : type descriptor
186 ****************************************************************************/
188 void parseFields(parse_file
*in
, type_descriptor
*t
, sequence
* unnamed_types
,
194 sequence_init(&(t
->fields
));
196 token
= getToken(in
);
197 while(in
->type
== NAME
&& strcmp(token
,"field") == 0) {
198 f
= (field
*)memAlloc(sizeof(field
));
199 sequence_push(&(t
->fields
),f
);
202 f
->name
= (char *)allocAndCopy(getName(in
));
204 f
->description
= (char *)allocAndCopy(getQuotedString(in
));
206 f
->type
= parseType(in
,NULL
, unnamed_types
, named_types
);
209 token
= getToken(in
);
210 if(in
->type
== COMA
) token
= getName(in
);
211 else ungetToken(in
); // no more fields, it must be a ')'
214 if(in
->type
== NAME
&& strcmp(token
,"field") != 0)
215 in
->error(in
,"not a field");
219 /*****************************************************************************
221 * parseType : get type information, type can be :
223 * int(size,fmt); uint(size,fmt); float(size,fmt);
224 * string(fmt); enum(size,fmt,(label1,label2...))
226 * array(arraySize, type); sequence(lengthSize,type)
227 * struct(field(name,type,description)...)
231 * in : input file handle
232 * inType : a type descriptor
234 * type_descriptor* : a type descriptor
235 ****************************************************************************/
237 type_descriptor
*parseType(parse_file
*in
, type_descriptor
*inType
,
238 sequence
* unnamed_types
, table
* named_types
)
244 t
= (type_descriptor
*) memAlloc(sizeof(type_descriptor
));
248 sequence_push(unnamed_types
,t
);
254 if(strcmp(token
,"struct") == 0) {
257 parseFields(in
,t
, unnamed_types
, named_types
);
260 else if(strcmp(token
,"array") == 0) {
263 t
->size
= getNumber(in
);
265 t
->nested_type
= parseType(in
,NULL
, unnamed_types
, named_types
);
268 else if(strcmp(token
,"sequence") == 0) {
271 t
->size
= getSize(in
);
273 t
->nested_type
= parseType(in
,NULL
, unnamed_types
, named_types
);
276 else if(strcmp(token
,"enum") == 0) {
278 sequence_init(&(t
->labels
));
280 t
->size
= getSize(in
);
282 token
= getToken(in
);
283 if(in
->type
== QUOTEDSTRING
){
284 t
->fmt
= allocAndCopy(token
);
286 }else ungetToken(in
);
289 token
= getToken(in
);
290 while(in
->type
!= RPARENTHESIS
) {
291 if(in
->type
!= NAME
) in
->error(in
,"Name token was expected");
292 car
= allocAndCopy(token
);
293 token
= getToken(in
);
294 if(in
->type
== COMA
){
295 sequence_push(&(t
->labels
),allocAndCopy(car
));
297 }else if(in
->type
== EQUAL
){ //label followed by '=' and a number, e.x. label1 = 1,
298 car
= appendString(car
, token
);
299 token
= getToken(in
);
300 if(in
->type
!= NUMBER
) in
->error(in
,"Number token was expected");
301 car
= appendString(car
, token
);
302 sequence_push(&(t
->labels
),allocAndCopy(car
));
303 token
= getToken(in
);
304 if(in
->type
== COMA
) token
= getName(in
);
307 sequence_push(&(t
->labels
),allocAndCopy(car
));
314 else if(strcmp(token
,"int") == 0) {
317 t
->size
= getSize(in
);
318 token
= getToken(in
);
319 if(in
->type
== COMA
) {
320 token
= getQuotedString(in
);
321 t
->fmt
= allocAndCopy(token
);
326 else if(strcmp(token
,"uint") == 0) {
329 t
->size
= getSize(in
);
330 token
= getToken(in
);
331 if(in
->type
== COMA
) {
332 token
= getQuotedString(in
);
333 t
->fmt
= allocAndCopy(token
);
338 else if(strcmp(token
,"float") == 0) {
341 t
->size
= getSize(in
);
342 token
= getToken(in
);
343 if(in
->type
== COMA
) {
344 token
= getQuotedString(in
);
345 t
->fmt
= allocAndCopy(token
);
350 else if(strcmp(token
,"string") == 0) {
353 token
= getToken(in
);
354 if(in
->type
== QUOTEDSTRING
) t
->fmt
= allocAndCopy(token
);
359 /* Must be a named type */
361 in
->error(in
,"Named type cannot refer to a named type");
364 sequence_pop(unnamed_types
);
365 return(find_named_type(token
, named_types
));
372 /*****************************************************************************
374 * find_named_type : find a named type from hash table
378 * type_descriptor * : a type descriptor
379 *****************************************************************************/
381 type_descriptor
* find_named_type(char *name
, table
* named_types
)
385 t
= table_find(named_types
,name
);
387 t
= (type_descriptor
*)memAlloc(sizeof(type_descriptor
));
388 t
->type_name
= allocAndCopy(name
);
391 table_insert(named_types
,allocAndCopy(name
),t
);
396 /*****************************************************************************
398 * parseTypeDefinition : get type information from type definition
400 * in : input file handle
401 *****************************************************************************/
403 void parseTypeDefinition(parse_file
* in
, sequence
* unnamed_types
,
411 t
= find_named_type(token
, named_types
);
414 if(t
->type
!= NONE
) in
->error(in
,"redefinition of named type");
415 parseType(in
,t
, unnamed_types
, named_types
);
421 /**************************************************************************
423 * getComa, getName, getNumber, getLParenthesis, getRParenthesis, getEqual
425 * Read a token from the input file, check its type, return it scontent.
428 * in , input file handle.
431 * address of token content.
433 **************************************************************************/
435 char *getName(parse_file
* in
)
439 token
= getToken(in
);
440 if(in
->type
!= NAME
) in
->error(in
,"Name token was expected");
444 int getNumber(parse_file
* in
)
448 token
= getToken(in
);
449 if(in
->type
!= NUMBER
) in
->error(in
, "Number token was expected");
453 char *getComa(parse_file
* in
)
457 token
= getToken(in
);
458 if(in
->type
!= COMA
) in
->error(in
, "Coma token was expected");
462 char *getLParenthesis(parse_file
* in
)
466 token
= getToken(in
);
467 if(in
->type
!= LPARENTHESIS
) in
->error(in
, "Left parenthesis was expected");
471 char *getRParenthesis(parse_file
* in
)
475 token
= getToken(in
);
476 if(in
->type
!= RPARENTHESIS
) in
->error(in
, "Right parenthesis was expected");
480 char *getQuotedString(parse_file
* in
)
484 token
= getToken(in
);
485 if(in
->type
!= QUOTEDSTRING
) in
->error(in
, "quoted string was expected");
489 char * getSemiColon(parse_file
*in
)
493 token
= getToken(in
);
494 if(in
->type
!= SEMICOLON
) in
->error(in
, "semicolon was expected");
498 char * getEqual(parse_file
*in
)
502 token
= getToken(in
);
503 if(in
->type
!= EQUAL
) in
->error(in
, "equal was expected");
507 /******************************************************************
509 * getToken, ungetToken
511 * Read a token from the input file and return its type and content.
512 * Line numbers are accounted for and whitespace/comments are skipped.
515 * in, input file handle.
518 * address of token content.
520 ******************************************************************/
522 void ungetToken(parse_file
* in
)
527 char *getToken(parse_file
* in
)
531 int pos
= 0, escaped
;
538 /* skip whitespace and comments */
540 while((car
= getc(fp
)) != EOF
) {
543 if(car1
== '*') skipComment(in
);
544 else if(car1
== '/') skipEOL(in
);
546 car1
= ungetc(car1
,fp
);
550 else if(car
== '\n') in
->lineno
++;
551 else if(!isspace(car
)) break;
560 in
->buffer
[pos
] = car
;
564 in
->type
= LPARENTHESIS
;
565 in
->buffer
[pos
] = car
;
569 in
->type
= RPARENTHESIS
;
570 in
->buffer
[pos
] = car
;
574 in
->type
= SEMICOLON
;
575 in
->buffer
[pos
] = car
;
580 in
->buffer
[pos
] = car
;
585 while((car
= getc(fp
)) != EOF
&& pos
< BUFFER_SIZE
) {
586 if(car
== '\\' && escaped
== 0) {
587 in
->buffer
[pos
] = car
;
592 if(car
== '"' && escaped
== 0) break;
593 if(car
== '\n' && escaped
== 0) {
594 in
->error(in
, "non escaped newline inside quoted string");
596 if(car
== '\n') in
->lineno
++;
597 in
->buffer
[pos
] = car
;
601 if(car
== EOF
) in
->error(in
,"no ending quotemark");
602 if(pos
== BUFFER_SIZE
) in
->error(in
, "quoted string token too large");
603 in
->type
= QUOTEDSTRING
;
607 in
->buffer
[pos
] = car
;
609 while((car
= getc(fp
)) != EOF
&& pos
< BUFFER_SIZE
) {
614 in
->buffer
[pos
] = car
;
617 if(car
== EOF
) ungetc(car
,fp
);
618 if(pos
== BUFFER_SIZE
) in
->error(in
, "number token too large");
621 else if(isalpha(car
)) {
624 while((car
= getc(fp
)) != EOF
&& pos
< BUFFER_SIZE
) {
629 in
->buffer
[pos
] = car
;
632 if(car
== EOF
) ungetc(car
,fp
);
633 if(pos
== BUFFER_SIZE
) in
->error(in
, "name token too large");
636 else in
->error(in
, "invalid character, unrecognized token");
642 void skipComment(parse_file
* in
)
645 while((car
= getc(in
->fp
)) != EOF
) {
646 if(car
== '\n') in
->lineno
++;
647 else if(car
== '*') {
650 if(car
== '/') return;
654 if(car
== EOF
) in
->error(in
,"comment begining with '/*' has no ending '*/'");
657 void skipEOL(parse_file
* in
)
660 while((car
= getc(in
->fp
)) != EOF
) {
666 if(car
== EOF
)ungetc(car
, in
->fp
);
672 if(c
== '_')return 1;
675 if((i
>=0 && i
<26) || (j
>=0 && j
<26)) return 1;
681 return (isalpha(c
) || isdigit(c
));
684 /*****************************************************************************
686 * checkNamedTypesImplemented : check if all named types have definition
687 ****************************************************************************/
689 void checkNamedTypesImplemented(table
* named_types
)
695 for(pos
= 0 ; pos
< named_types
->values
.position
; pos
++) {
696 t
= (type_descriptor
*) named_types
->values
.array
[pos
];
698 sprintf(str
,"named type '%s' has no definition",(char*)named_types
->keys
.array
[pos
]);
699 error_callback(NULL
,str
);
705 /*****************************************************************************
707 * generateChecksum : generate checksum for the facility
709 * facName : name of facility
711 * checksum : checksum for the facility
712 ****************************************************************************/
714 void generateChecksum( char* facName
, unsigned long * checksum
, sequence
* events
)
717 int pos
, nestedStruct
;
721 crc
= crc32(facName
);
722 for(pos
= 0; pos
< events
->position
; pos
++){
723 ev
= (event
*)(events
->array
[pos
]);
724 ev
->nested
= 0; //by default, event has no nested struct
725 crc
= partial_crc32(ev
->name
,crc
);
727 if(ev
->type
->type
!= STRUCT
){
728 sprintf(str
,"event '%s' has a type other than STRUCT",ev
->name
);
729 error_callback(NULL
, str
);
731 crc
= getTypeChecksum(crc
, ev
->type
,&nestedStruct
);
732 if(nestedStruct
) ev
->nested
= 1;
737 /*****************************************************************************
739 * getTypeChecksum : generate checksum by type info
741 * crc : checksum generated so far
742 * type : type descriptor containing type info
744 * unsigned long : checksum
745 *****************************************************************************/
747 unsigned long getTypeChecksum(unsigned long aCrc
, type_descriptor
* type
,
750 unsigned long crc
= aCrc
;
751 char * str
= NULL
, buf
[16];
752 int flag
= 0, pos
, max
, min
;
758 str
= intOutputTypes
[type
->size
];
761 str
= uintOutputTypes
[type
->size
];
764 str
= floatOutputTypes
[type
->size
];
767 str
= allocAndCopy("string");
771 str
= appendString("enum ", uintOutputTypes
[type
->size
]);
775 sprintf(buf
,"%d\0",type
->size
);
776 str
= appendString("array ",buf
);
780 sprintf(buf
,"%d\0",type
->size
);
781 str
= appendString("sequence ",buf
);
785 str
= allocAndCopy("struct");
789 error_callback(NULL
, "named type has no definition");
793 crc
= partial_crc32(str
,crc
);
796 if(type
->fmt
) crc
= partial_crc32(type
->fmt
,crc
);
798 if(type
->type
== ARRAY
|| type
->type
== SEQUENCE
){
799 dt
= type
->nested_type
->type
;
800 if(dt
== ARRAY
|| dt
== SEQUENCE
|| dt
== STRUCT
) *nestedStruct
+= 1;
801 crc
= getTypeChecksum(crc
,type
->nested_type
,nestedStruct
);
802 }else if(type
->type
== STRUCT
){
803 if(type
->fields
.position
!= 0){//not a empty struct
805 for(pos
=0; pos
< type
->fields
.position
; pos
++){
807 fld
= (field
*) type
->fields
.array
[pos
];
808 crc
= partial_crc32(fld
->name
,crc
);
809 if(fld
->type
->type
== STRUCT
) min
++;
810 crc
= getTypeChecksum(crc
, fld
->type
,&min
);
811 if(min
>max
) max
= min
;
813 *nestedStruct
+= max
;
815 }else if(type
->type
== ENUM
){
816 for(pos
= 0; pos
< type
->labels
.position
; pos
++)
817 crc
= partial_crc32((char*)type
->labels
.array
[pos
],crc
);
824 /* Event type descriptors */
825 void freeType(type_descriptor
* tp
)
830 if(tp
->fmt
!= NULL
) free(tp
->fmt
);
831 if(tp
->type
== ENUM
) {
832 for(pos2
= 0; pos2
< tp
->labels
.position
; pos2
++) {
833 free(tp
->labels
.array
[pos2
]);
835 sequence_dispose(&(tp
->labels
));
837 if(tp
->type
== STRUCT
) {
838 for(pos2
= 0; pos2
< tp
->fields
.position
; pos2
++) {
839 f
= (field
*) tp
->fields
.array
[pos2
];
841 free(f
->description
);
844 sequence_dispose(&(tp
->fields
));
848 void freeNamedType(table
* t
)
851 type_descriptor
* td
;
853 for(pos
= 0 ; pos
< t
->keys
.position
; pos
++) {
854 free((char *)t
->keys
.array
[pos
]);
855 td
= (type_descriptor
*)t
->values
.array
[pos
];
861 void freeTypes(sequence
*t
)
867 for(pos
= 0 ; pos
< t
->position
; pos
++) {
868 tp
= (type_descriptor
*)t
->array
[pos
];
874 void freeEvents(sequence
*t
)
879 for(pos
= 0 ; pos
< t
->position
; pos
++) {
880 ev
= (event
*) t
->array
[pos
];
882 free(ev
->description
);
889 /* Extensible array */
891 void sequence_init(sequence
*t
)
895 t
->array
= (void **)memAlloc(t
->size
* sizeof(void *));
898 void sequence_dispose(sequence
*t
)
905 void sequence_push(sequence
*t
, void *elem
)
909 if(t
->position
>= t
->size
) {
911 t
->array
= (void **)memAlloc(t
->size
* 2 * sizeof(void *));
912 memcpy(t
->array
, tmp
, t
->size
* sizeof(void *));
913 t
->size
= t
->size
* 2;
916 t
->array
[t
->position
] = elem
;
920 void *sequence_pop(sequence
*t
)
922 return t
->array
[t
->position
--];
926 /* Hash table API, implementation is just linear search for now */
928 void table_init(table
*t
)
930 sequence_init(&(t
->keys
));
931 sequence_init(&(t
->values
));
934 void table_dispose(table
*t
)
936 sequence_dispose(&(t
->keys
));
937 sequence_dispose(&(t
->values
));
940 void table_insert(table
*t
, char *key
, void *value
)
942 sequence_push(&(t
->keys
),key
);
943 sequence_push(&(t
->values
),value
);
946 void *table_find(table
*t
, char *key
)
949 for(pos
= 0 ; pos
< t
->keys
.position
; pos
++) {
950 if(strcmp((char *)key
,(char *)t
->keys
.array
[pos
]) == 0)
951 return(t
->values
.array
[pos
]);
956 void table_insert_int(table
*t
, int *key
, void *value
)
958 sequence_push(&(t
->keys
),key
);
959 sequence_push(&(t
->values
),value
);
962 void *table_find_int(table
*t
, int *key
)
965 for(pos
= 0 ; pos
< t
->keys
.position
; pos
++) {
966 if(*key
== *(int *)t
->keys
.array
[pos
])
967 return(t
->values
.array
[pos
]);
973 /* Concatenate strings */
975 char *appendString(char *s
, char *suffix
)
979 tmp
= (char *)memAlloc(strlen(s
) + strlen(suffix
) + 1);
This page took 0.049668 seconds and 4 git commands to generate.