Go to: Contents; Previous section; Beginning of section; Next file in section; Previous file in section.
Line Name
----- ----
33 cond_token
616 c_parser
265 evaluate_if
282 evaluate_ifdef
299 get_token
239 iskeyword
200 new_source_line
133 trace_parser
152 trace_parser_int
176 trace_parser_state
BEGINNING OF FILE
1: /****************************************************************************/
2: /* */
3: /* FACILITY: Routine Analyzer */
4: /* */
5: /* MODULE: C Language Parser */
6: /* */
7: /* AUTHOR: Steve Branam, Network Product Support Group, Digital */
8: /* Equipment Corporation, Littleton, MA, USA. */
9: /* */
10: /* DESCRIPTION: This module contains the source parser for C language */
11: /* source files. Note that this particular implementation is a very */
12: /* rudimentary state-driven parser. While it is reasonably functional, it */
13: /* is possible that it may become confused by unusual but otherwise valid */
14: /* language constructs. */
15: /* */
16: /* REVISION HISTORY: */
17: /* */
18: /* V0.1-00 24-AUG-1994 Steve Branam */
19: /* */
20: /* Original version. */
21: /* */
22: /****************************************************************************/
23:
24: #include <stdio.h>
25: #include <ctype.h>
26: #include "ranalyzer.h"
27: #include "parser.h"
28:
29: #define MAX_DQUOTE_LEN 512 /* Just a guess. */
30: #define MAX_SQUOTE_LEN 4 /* '\123' */
31:
32:
ROUTINE cond_token. Go to:
Next routine in file; Routines in this file.
33: #define cond_token(t) (copy ? t : SPACE)
END cond_token. Go to: Beginning of routine.
34:
35: typedef enum
36: {
37: NO_MACRO,
38: IN_MACRO
39: } c_macro_states;
40:
41: typedef enum
42: {
43: FIND_START,
44: FIND_END_ALNUM,
45: FIND_END_NUMBER,
46: FIND_END_SPACE,
47: FIND_END_DIRECTIVE,
48: FIND_END_DQUOTED,
49: FIND_END_SQUOTED,
50: FIND_END_COMMENT
51: } c_scanner_states;
52:
53: typedef enum
54: {
55: FIND_IDENT,
56: FIND_DEF_LPAREN,
57: FIND_DEF_RPAREN,
58: FIND_LBRACE_OR_SEMICOLON,
59: FIND_LBRACE,
60: FIND_MACRO_IDENT,
61: FIND_MACRO_LPAREN,
62: IN_ROUTINE,
63: FIND_REF_LPAREN
64: } c_parser_states;
65:
66: static char
67: *mPSNames[] = {
68: "FIND_IDENT",
69: "FIND_DEF_LPAREN",
70: "FIND_DEF_RPAREN",
71: "FIND_LBRACE_OR_SEMICOLON",
72: "FIND_LBRACE",
73: "FIND_MACRO_IDENT",
74: "FIND_MACRO_LPAREN",
75: "IN_ROUTINE",
76: "FIND_REF_LPAREN"
77: };
78:
79: typedef enum
80: {
81: END_C_SOURCE,
82: LPAREN,
83: RPAREN,
84: LBRACE,
85: RBRACE,
86: SEMICOLON,
87: IDENTIFIER,
88: KEYWORD,
89: MACBEGIN,
90: SPACE,
91: OTHER
92: } c_token_types;
93:
94: static char
95: *keywords[] = { "auto",
96: "break",
97: "case",
98: "char",
99: "continue",
100: "default",
101: "do",
102: "double",
103: "else",
104: "entry",
105: "enum",
106: "extern",
107: "float",
108: "for",
109: "goto",
110: "if",
111: "int",
112: "long",
113: "register",
114: "return",
115: "sizeof",
116: "short",
117: "static",
118: "struct",
119: "switch",
120: "typedef",
121: "union",
122: "unsigned",
123: "void",
124: "while",
125: NULL };
126:
127: static int /* Statement char count. */
128: statement;
129: static int /* Comment char count. */
130: comment;
131:
132: /*************************************************************************++*/
ROUTINE trace_parser. Go to:
Next routine in file; Routines in this file.
133: void trace_parser(
134: /* Write a parser trace message to the listing file. Listing must be */
135: /* enabled. Parser tracing is assumed to be enabled. */
136:
137: char *aTraceStr
138: /* (READ, BY ADDR): */
139: /* String to write to listing file. */
140:
141: ) /* No return value. */
142: /*****************************************************************--*/
143:
144: {
145: if (list_enabled()) {
146: fputs(aTraceStr, list_file());
147: restore_list_column();
148: }
149: }
END trace_parser. Go to: Beginning of routine.
150:
151: /*************************************************************************++*/
ROUTINE trace_parser_int. Go to:
Next routine in file; Routines in this file.
152: void trace_parser_int(
153: /* Write a parser trace message containing one integer value to the listing */
154: /* file. Listing must be enabled. Parser tracing is assumed to be enabled. */
155:
156: char *aTraceStr,
157: /* (READ, BY ADDR): */
158: /* String (including one integer printf format control) to */
159: /* write to listing file. */
160:
161: int vInt
162: /* (READ, BY VAL): */
163: /* Integer value to write in string. */
164:
165: ) /* No return value. */
166: /*****************************************************************--*/
167:
168: {
169: if (list_enabled()) {
170: fprintf(list_file(), aTraceStr, vInt);
171: restore_list_column();
172: }
173: }
END trace_parser_int. Go to: Beginning of routine.
174:
175: /*************************************************************************++*/
ROUTINE trace_parser_state. Go to:
Next routine in file; Routines in this file.
176: void trace_parser_state(
177: /* Write a parser state change trace message to the listing file. Listing */
178: /* must be enabled. Parser tracing is assumed to be enabled. */
179:
180: char *aFromName,
181: /* (READ, BY ADDR): */
182: /* Name string for state changing from. */
183:
184: char *aToName
185: /* (READ, BY ADDR): */
186: /* Name string for state changing to. */
187:
188: ) /* No return value. */
189: /*****************************************************************--*/
190:
191: {
192: if (list_enabled()) {
193: fprintf(list_file(), "\nTRACE: Parser state change: %s to %s\n",
194: aFromName, aToName);
195: restore_list_column();
196: }
197: }
END trace_parser_state. Go to: Beginning of routine.
198:
199: /*************************************************************************++*/
ROUTINE new_source_line. Go to:
Next routine in file; Routines in this file.
200: void new_source_line(
201: /* Updates source line counters when a new line is found. */
202:
203: SOURCEFILE
204: *aSourceRecord
205: /* (MODIFY, BY ADDR): */
206: /* Source file information record. The line count */
207: /* statistics will be updated. */
208:
209: ) /* No return value */
210: /*****************************************************************--*/
211:
212: {
213: /*
214: ** Classify the source line just completed as either mixed
215: ** statements/comments, statements only, comments only, or blank, and
216: ** increment the appropriate source record counters.
217: */
218:
219: if (statement && comment) {
220: inc_source_mixed(aSourceRecord);
221: }
222: else if (statement){
223: inc_source_statements(aSourceRecord);
224: }
225: else if (comment) {
226: inc_source_comments(aSourceRecord);
227: }
228: else {
229: inc_source_empty(aSourceRecord);
230: }
231:
232: statement = 0; /* Reset counters for next */
233: comment = 0; /* line. */
234:
235: new_list_line(aSourceRecord);
236: }
END new_source_line. Go to: Beginning of routine.
237:
238: /*************************************************************************++*/
ROUTINE iskeyword. Go to:
Next routine in file; Routines in this file.
239: static int iskeyword(
240: /* Determines whether or not an alphanumeric token is a source language */
241: /* keyword. */
242:
243: char *aKeywords[],
244: /* (READ, BY ADDR): */
245: /* List of known source language keyword string pointers, in */
246: /* alphabetical order, terminated by NULL entry. */
247:
248: char *aToken
249: /* (READ, BY ADDR): */
250: /* Token string to check. */
251:
252: ) /* Returns status of comparison: */
253: /* 1 - Token is a keyword. */
254: /* 0 - Token is not a keyword. */
255: /*****************************************************************--*/
256:
257: {
258: int cmpstat; /* Comparison status. */
259:
260: while (*aKeywords != NULL && (cmpstat = strcmp(*aKeywords++, aToken)) < 0);
261: return !cmpstat;
262: }
END iskeyword. Go to: Beginning of routine.
263:
264: /*************************************************************************++*/
ROUTINE evaluate_if. Go to:
Next routine in file; Routines in this file.
265: static int evaluate_if(
266: /* Evaluates a #if conditional compilation directive. */
267: /* */
268: /* WARNING: This is just a dummy version for now. */
269:
270: char *aCondition
271: /* (READ, BY ADDR): */
272: /* Condition string to be evaluated. */
273:
274: ) /* Returns boolean flag to indicate results of evaluation. */
275: /*****************************************************************--*/
276:
277: {
278: return atoi(aCondition); /* Handle simple numeric constant */
279: }
END evaluate_if. Go to: Beginning of routine.
280:
281: /*************************************************************************++*/
ROUTINE evaluate_ifdef. Go to:
Next routine in file; Routines in this file.
282: static int evaluate_ifdef(
283: /* Evaluates a #ifdef conditional compilation directive. */
284: /* */
285: /* WARNING: This is just a dummy version for now. */
286:
287: char *aCondition
288: /* (READ, BY ADDR): */
289: /* Condition string to be evaluated. */
290:
291: ) /* Returns boolean flag to indicate results of evaluation. */
292: /*****************************************************************--*/
293:
294: {
295: return 0; /* Nothing is defined right now. */
296: }
END evaluate_ifdef. Go to: Beginning of routine.
297:
298: /*************************************************************************++*/
ROUTINE get_token. Go to:
Next routine in file; Routines in this file.
299: static get_token(
300: /* Source file input scanner. Reads the next lexical token from the source */
301: /* file and accumulates source line statistics. */
302:
303: FILE *aSourceFile,
304: /* (READ, BY ADDR): */
305: /* Source file containing C language. */
306:
307: SOURCEFILE
308: *aSourceRecord,
309: /* (MODIFY, BY ADDR): */
310: /* Source file information record. The line count */
311: /* statistics will be updated. */
312:
313: char *aToken
314: /* (WRITE, BY ADDR): */
315: /* String buffer to receive token. */
316:
317: ) /* Returns code indicating which type of token was found: */
318: /* END_C_SOURCE - End of the source file. */
319: /* LPAREN - Left parenthesis. */
320: /* RPAREN - Right parenthesis. */
321: /* LBRACE - Left brace. */
322: /* RBRACE - Right brace. */
323: /* SEMICOLON - Semicolon. */
324: /* IDENTIFIER - Routine or data identifier */
325: /* KEYWORD - C language keyword. */
326: /* MACBEGIN - Beginning of macro. */
327: /* SPACE - Whitespace. */
328: /* OTHER - Some other type of token. */
329: /*****************************************************************--*/
330:
331: {
332: int ch; /* Input character. */
333: int quotelen; /* Length of quoted token. */
334: c_scanner_states /* Scanner state. */
335: state = FIND_START;
336: char *nextchar = aToken; /* Pointer to next char */
337: /* position in aToken. */
338: char condbuf[256]; /* Conditional directive buf. */
339: static int /* Conditional compilation copy */
340: copy = 1; /* flag. */
341: static c_macro_states /* Macro state. */
342: macro = NO_MACRO;
343:
344: do {
345: ch = fgetc(aSourceFile);
346: switch (state) {
347: case FIND_START:
348: list_char(ch);
349: if (isalpha(ch) || ch == '_' || ch == '$') {
350: state = FIND_END_ALNUM;
351: *nextchar++ = ch;
352: statement++;
353: }
354: else if (isdigit(ch)) {
355: state = FIND_END_NUMBER;
356: *nextchar++ = ch;
357: statement++;
358: }
359: else if (isspace(ch)) {
360: if (ch == '\n') {
361: if (macro == IN_MACRO) {/* Special case: if end of line */
362: macro = NO_MACRO; /* in a macro, this is really */
363: ungetc(ch, aSourceFile);
364: return cond_token(RBRACE); /* end of a "routine" */
365: } /* definition. */
366: else {
367: new_source_line(aSourceRecord);
368: }
369: }
370: state = FIND_END_SPACE;
371: }
372: else {
373: switch (ch) {
374: case '(':
375: statement++;
376: return cond_token(LPAREN);
377: break;
378: case ')':
379: statement++;
380: return cond_token(RPAREN);
381: break;
382: case '{':
383: statement++;
384: return cond_token(LBRACE);
385: break;
386: case '}':
387: statement++;
388: return cond_token(RBRACE);
389: break;
390: case ';':
391: statement++;
392: return cond_token(SEMICOLON);
393: break;
394: case '#':
395: statement++;
396: *nextchar++ = ch;
397: state = FIND_END_DIRECTIVE;
398: break;
399: case '"':
400: statement++;
401: state = FIND_END_DQUOTED;
402: quotelen = 0;
403: break;
404: case '\'':
405: statement++;
406: state = FIND_END_SQUOTED;
407: quotelen = 0;
408: break;
409: case '/':
410: ch = fgetc(aSourceFile);
411: if (ch == '*') {
412: list_char(ch);
413: state = FIND_END_COMMENT;
414: comment += 2;
415: }
416: else {
417: ungetc(ch, aSourceFile);
418: statement++;
419: }
420: break;
421: default:
422: if (ch != EOF) {
423: *nextchar++ = ch;
424: *nextchar = '\0';
425: statement++;
426: return cond_token(OTHER);
427: }
428: }
429: }
430: break;
431: case FIND_END_ALNUM:
432: if (isalnum(ch) || ch == '_' || ch == '$') {
433: list_char(ch);
434: *nextchar++ = ch;
435: statement++;
436: }
437: else {
438: ungetc(ch, aSourceFile);
439: *nextchar = '\0';
440: if (iskeyword(keywords, aToken)) {
441: return cond_token(KEYWORD);
442: }
443: else {
444: return cond_token(IDENTIFIER);
445: }
446: }
447: break;
448: case FIND_END_NUMBER:
449: if (isdigit(ch)) {
450: list_char(ch);
451: *nextchar++ = ch;
452: statement++;
453: }
454: else {
455: ungetc(ch, aSourceFile);
456: *nextchar = '\0';
457: return cond_token(OTHER);
458: }
459: break;
460: case FIND_END_SPACE:
461: if (isspace(ch)) {
462: list_char(ch);
463: if (ch == '\n') {
464: if (macro == IN_MACRO) {/* Special case: if end of line */
465: macro = NO_MACRO; /* in a macro, this is really */
466: ungetc(ch, aSourceFile);
467: return cond_token(RBRACE); /* the end of a "routine" */
468: } /* definition. */
469: else {
470: new_source_line(aSourceRecord);
471: }
472: }
473: }
474: else {
475: ungetc(ch, aSourceFile);
476: *nextchar = '\0';
477: return cond_token(SPACE);
478: }
479: break;
480: case FIND_END_DIRECTIVE:
481: if (isalpha(ch)) {
482: list_char(ch);
483: *nextchar++ = ch;
484: statement++;
485: }
486: else {
487: ungetc(ch, aSourceFile);
488: *nextchar = '\0';
489: if (!strcmp(aToken, "#define")) {
490: macro = IN_MACRO;
491: return cond_token(MACBEGIN);
492: }
493: else if (!strcmp(aToken, "#if")) {
494: fgets(condbuf, sizeof(condbuf), aSourceFile);
495: if (list_enabled()) {
496: fputs(condbuf, list_file());
497: }
498: new_source_line(aSourceRecord);
499: copy = evaluate_if(condbuf);
500: return SPACE;
501: }
502: else if (!strcmp(aToken, "#ifdef")) {
503: fgets(condbuf, sizeof(condbuf), aSourceFile);
504: if (list_enabled()) {
505: fputs(condbuf, list_file());
506: }
507: new_source_line(aSourceRecord);
508: copy = evaluate_ifdef(condbuf);
509: return SPACE;
510: }
511: else if (!strcmp(aToken, "#ifndef")) {
512: fgets(condbuf, sizeof(condbuf), aSourceFile);
513: if (list_enabled()) {
514: fputs(condbuf, list_file());
515: }
516: new_source_line(aSourceRecord);
517: copy = !evaluate_ifdef(condbuf);
518: return SPACE;
519: }
520: else if (!strcmp(aToken, "#else")) {
521: copy = !copy;
522: return SPACE;
523: }
524: else if (!strcmp(aToken, "#endif")) {
525: copy = 1;
526: return SPACE;
527: }
528: else
529: {
530: return cond_token(OTHER);
531: }
532: }
533: break;
534: case FIND_END_DQUOTED:
535: list_char(ch);
536: if (ch == '"') {
537: statement++;
538: return cond_token(OTHER);
539: }
540: else if (ch == '\\') { /* Check for escape seq. */
541: statement++;
542: quotelen++;
543: ch = fgetc(aSourceFile);
544: list_char(ch);
545: statement++;
546: quotelen++;
547: }
548: else if (ch == '\n') {
549: new_source_line(aSourceRecord);
550: }
551: else if (quotelen > MAX_DQUOTE_LEN) {
552: printf(
553: "WARNING: Suspected unterminated double quote at line %d of %s\n",
554: source_line(aSourceRecord), source_name(aSourceRecord));
555: return cond_token(OTHER);
556: }
557: else {
558: statement++;
559: quotelen++;
560: }
561: break;
562: case FIND_END_SQUOTED:
563: list_char(ch);
564: if (ch == '\'') {
565: ch = fgetc(aSourceFile);
566: if (ch == '\'') {
567: statement++;
568: list_char(ch);
569: }
570: else {
571: ungetc(ch, aSourceFile);
572: }
573: statement++;
574: return cond_token(OTHER);
575: }
576: else if (ch == '\n' || quotelen > MAX_SQUOTE_LEN) {
577: new_source_line(aSourceRecord);
578: printf(
579: "WARNING: Suspected unterminated single quote at line %d of %s\n",
580: source_line(aSourceRecord), source_name(aSourceRecord));
581: return cond_token(OTHER);
582: }
583: else {
584: statement++;
585: quotelen++;
586: }
587: break;
588: case FIND_END_COMMENT:
589: list_char(ch);
590: if (ch == '*') {
591: ch = fgetc(aSourceFile);
592: if (ch == '/') {
593: list_char(ch);
594: state = FIND_START;
595: comment += 2;
596: }
597: else {
598: ungetc(ch, aSourceFile);
599: comment++;
600: }
601: }
602: else if (ch == '\n') {
603: new_source_line(aSourceRecord);
604: }
605: else {
606: comment++;
607: }
608: break;
609: }
610: } while (ch != EOF);
611: copy = 1;
612: return END_C_SOURCE;
613: }
END get_token. Go to: Beginning of routine.
614:
615: /*************************************************************************++*/
ROUTINE c_parser. Go to:
Next routine in file; Routines in this file.
616: language_element c_parser(
617: /* Parses C source language statements, looking for routine definition */
618: /* begin and end, and routine references. Retrieves the next language */
619: /* element in the source file. */
620: /* */
621: /* Note that this version is a very simple-minded parser, and has several */
622: /* limitations. It is not able to identify function pointer usages as */
623: /* routine references. It may also be confused by other legal constructs. */
624:
625: FILE *aSourceFile,
626: /* (READ, BY ADDR): */
627: /* Source file containing C language. Must be opened by */
628: /* caller. */
629:
630: SOURCEFILE
631: *aSourceRecord,
632: /* (READ, BY ADDR): */
633: /* Source file information record. */
634:
635: char *aElement,
636: /* (WRITE, BY ADDR): */
637: /* String buffer that will receive the recognized source */
638: /* language element. */
639:
640: long *aSourceLine
641: /* (WRITE, BY ADDR): */
642: /* Buffer that will receive the line number of aElement. */
643:
644: ) /* Returns one of the following values indicating the type of */
645: /* element output in aElement: */
646: /* PARSE_ERROR - An error was detected in the input */
647: /* stream. */
648: /* END_OF_SOURCE - The normal end of file was found. */
649: /* ROUTINE_DEF_BEGIN - The beginning of a routine definition */
650: /* was found. */
651: /* ROUTINE_DEF_END - The end of the current routine */
652: /* definition was found. */
653: /* ROUTINE_REF - A routine reference (call) was found. */
654: /*****************************************************************--*/
655:
656: {
657: static c_parser_states /* Parser state. */
658: state = FIND_IDENT;
659: static int /* Nested braces level. */
660: blevel;
661: static char /* Name of current routine. */
662: curdefname[MAX_ROUTINE_NAME + 1];
663: int plevel; /* Nested parenthesis level. */
664: c_token_types /* Type of source token. */
665: tokentype;
666: char token[MAX_ROUTINE_NAME + 1]; /* Source token buffer. */
667:
668: /*
669: ** This function operates as a state machine. The states represent the
670: ** various tokens expected next in the token stream, according to C syntax.
671: ** Whenever a routine definition beginning or end, or routine reference, is
672: ** recognized, the parser returns to the caller. However, context is
673: ** maintained between calls to the parser via static state variables.
674: */
675:
676: do {
677: tokentype = get_token(aSourceFile, aSourceRecord, token);
678: switch (state) {
679: case FIND_IDENT:
680: if (tokentype == IDENTIFIER) {
681: strcpy(aElement, token);
682: *aSourceLine = source_line(aSourceRecord);
683: change_pstate(FIND_DEF_LPAREN);
684: }
685: else if (tokentype == MACBEGIN) {
686: change_pstate(FIND_MACRO_IDENT);
687: }
688: break;
689: case FIND_DEF_LPAREN:
690: if (tokentype == LPAREN) {
691: change_pstate(FIND_DEF_RPAREN);
692: paren_level_zero();
693: }
694: else if (tokentype == IDENTIFIER) {
695: strcpy(aElement, token);
696: *aSourceLine = source_line(aSourceRecord);
697: }
698: else if (tokentype != SPACE) {
699: change_pstate(FIND_IDENT);
700: }
701: break;
702: case FIND_DEF_RPAREN:
703: if (tokentype == RPAREN) {
704: if (plevel) {
705: paren_level_dec();
706: }
707: else {
708: change_pstate(FIND_LBRACE_OR_SEMICOLON);
709: }
710: }
711: else if (tokentype == LPAREN) {
712: paren_level_inc();
713: }
714: break;
715: case FIND_LBRACE_OR_SEMICOLON:
716: if (tokentype == LBRACE) {
717: change_pstate(IN_ROUTINE);
718: block_level_zero();
719: strcpy(curdefname, token);
720: return ROUTINE_DEF_BEGIN;
721: } /* Forward or external */
722: else if (tokentype == SEMICOLON) { /* declaration. */
723: change_pstate(FIND_IDENT);
724: }
725: else if (tokentype != SPACE) { /* Parameter declarations. */
726: change_pstate(FIND_LBRACE);
727: }
728: break;
729: case FIND_LBRACE:
730: if (tokentype == LBRACE) { /* Keep grabbing tokens */
731: change_pstate(IN_ROUTINE); /* until left brace. */
732: block_level_zero();
733: strcpy(curdefname, token);
734: return ROUTINE_DEF_BEGIN;
735: }
736: #if 0
737: else if (tokentype != SPACE) {
738: change_pstate(FIND_IDENT);
739: }
740: #endif
741: break;
742: case FIND_MACRO_IDENT:
743: if (tokentype == IDENTIFIER) {
744: strcpy(aElement, token);
745: *aSourceLine = source_line(aSourceRecord);
746: change_pstate(FIND_MACRO_LPAREN);
747: }
748: else if (tokentype != SPACE) {
749: change_pstate(FIND_IDENT);
750: }
751: break;
752: case FIND_MACRO_LPAREN:
753: if (tokentype == LPAREN) {
754: change_pstate(IN_ROUTINE);
755: strcpy(curdefname, token);
756: return ROUTINE_DEF_BEGIN;
757: }
758: else { /* Cannot tolerate SPACE here */
759: change_pstate(FIND_IDENT);
760: }
761: break;
762: case IN_ROUTINE:
763: if (tokentype == LBRACE) {
764: block_level_inc();
765: }
766: else if (tokentype == RBRACE) {
767: if (blevel == 0) {
768: trace_blmsg(BLEND);
769: change_pstate(FIND_IDENT);
770: *aSourceLine = source_line(aSourceRecord);
771: strcpy(aElement, curdefname);
772: return ROUTINE_DEF_END;
773: }
774: else {
775: block_level_dec();
776: }
777: }
778: else if (tokentype == IDENTIFIER) {
779: strcpy(aElement, token);
780: *aSourceLine = source_line(aSourceRecord);
781: change_pstate(FIND_REF_LPAREN);
782: }
783: else if (tokentype == END_C_SOURCE) {
784: printf("ERROR: Unexpected end of file %s\n",
785: source_name(aSourceRecord));
786: return PARSE_ERROR;
787: }
788: break;
789: case FIND_REF_LPAREN:
790: if (tokentype != SPACE) {
791: change_pstate(IN_ROUTINE);
792: if (tokentype == RBRACE) {
793: /* Must be scanner finding end */
794: /* of macro, calling it rbrace. */
795: if (blevel == 0) { /* Treat as end of routine. */
796: trace_blmsg(
797: "\nTRACE: brace level already 0 (assuming end of macro)\n");
798: change_pstate(FIND_IDENT);
799: *aSourceLine = source_line(aSourceRecord);
800: strcpy(aElement, curdefname);
801: return ROUTINE_DEF_END;
802: }
803: else { /* Must be end of data */
804: block_level_dec(); /* initializer list. */
805: trace_blmsg("(assuming end of data initializer)\n");
806: }
807: }
808: }
809: if (tokentype == LPAREN) {
810: return ROUTINE_REF;
811: }
812: break;
813: }
814: } while (tokentype != END_C_SOURCE);
815: change_pstate(FIND_IDENT);
816: return END_OF_SOURCE;
817: }
END c_parser. Go to: Beginning of routine.
END OF FILE
TOTAL: 10 routines, 67 Avg Length
Go to: Contents; Previous section; Beginning of section; Next file in section; Previous file in section.