@Routine Analyzer Source File Analysis - cparser.c6

cparser.c Source Code

LGo to: Contents; Previous section; Beginning of section; Next file in section; Previous file in section.

Q

Routines In This File (Alphabetical)



 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_int1  176 trace_parser_state


BEGINNING OF FILE


V     1: /****************************************************************************/     2: /*									    */1     3: /*  FACILITY:	Routine Analyzer					    */     4: /*									    */0     5: /*  MODULE:	C Language Parser					    */     6: /*									    */O     7: /*  AUTHOR:	Steve Branam, Network Product Support Group, Digital	    */>     8: /*		Equipment Corporation, Littleton, MA, USA.		    */     9: /*									    */U    10: /*  DESCRIPTION: This module contains the source parser for C language	    */S    11: /*  source files. Note that this particular implementation is a very	    */V    12: /*  rudimentary state-driven parser. While it is reasonably functional, it  */V    13: /*  is possible that it may become confused by unusual but otherwise valid  */,    14: /*  language constructs.						    */    15: /*									    */*    16: /*  REVISION HISTORY:							    */    17: /*									    */7    18: /*  V0.1-00 24-AUG-1994 Steve Branam					    */    19: /*									    */(    20: /*	Original version.						    */    21: /*									    */V    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.	    */8    30: #define MAX_SQUOTE_LEN	    4			/* '\123'		    */    31:     32: 

cROUTINE cond_token. Go to: mNext routine in file; Routines in this file.



0    33: #define cond_token(t)	(copy ? t : SPACE)
HEND 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;8   129: static  int				    /* Comment char count.	    */   130: 	comment;   131: V   132: /*************************************************************************++*/

eROUTINE trace_parser. Go to: mNext routine in file; Routines in this file.



   133: void trace_parser(S   134: /* Write a parser trace message to the listing file. Listing must be	    */E   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.      					    */O   142: 	/*****************************************************************--*/   143: 	   144: {!   145:     if (list_enabled()) {'   146: 	fputs(aTraceStr, list_file());   147: 	restore_list_column();
   148:     }	   149: }
JEND trace_parser. Go to: Beginning of routine.





   150: V   151: /*************************************************************************++*/

iROUTINE trace_parser_int. Go to: mNext routine in file; Routines in this file.



   152: void trace_parser_int(V   153: /* Write a parser trace message containing one integer value to the listing */V   154: /* file. Listing must be enabled. Parser tracing is assumed to be enabled.  */   155:    156:     char    *aTraceStr,-   157: 	    /* (READ, BY ADDR):  					    */N   158: 	    /* String (including one integer printf format control) to	    */1   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.      					    */O   166: 	/*****************************************************************--*/   167: 	   168: {!   169:     if (list_enabled()) {/   170: 	fprintf(list_file(), aTraceStr, vInt);   171: 	restore_list_column();
   172:     }	   173: }
NEND trace_parser_int. Go to: Beginning of routine.





   174: V   175: /*************************************************************************++*/

kROUTINE trace_parser_state. Go to: mNext routine in file; Routines in this file.



    176: void trace_parser_state(V   177: /* Write a parser state change trace message to the listing file. Listing   */L   178: /* must be enabled. Parser tracing is assumed to be enabled.		    */   179:    180:     char    *aFromName,r-   181: 	    /* (READ, BY ADDR):  					    */a=   182: 	    /* Name string for state changing from.			    */l
   183: 	    t   184:     char    *aToName-   185: 	    /* (READ, BY ADDR):  					    */i;   186: 	    /* Name string for state changing to.			    */ 
   187: 	     .   188: )	/* No return value.      					    */O   189: 	/*****************************************************************--*/s   190: 	   191: {/!   192:     if (list_enabled()) { I   193: 	fprintf(list_file(), "\nTRACE: Parser state change: %s to %s\n","!   194: 	    aFromName, aToName);0   195: 	restore_list_column();H
   196:     }"	   197: }f
PEND trace_parser_state. Go to: Beginning of routine.





H   198: V   199: /*************************************************************************++*/

hROUTINE new_source_line. Go to: mNext routine in file; Routines in this file.

*

    200: void new_source_line(3I   201: /* Updates source line counters when a new line is found.		    */    202:    203:     SOURCEFILE   204: 	    *aSourceRecord	*   205: 		/* (MODIFY, BY ADDR):					    */B   206: 		/* Source file information record. The line count	    */2   207: 		/* statistics will be updated.				    */   208: (   209: )	/* No return value						    */O   210: 	/*****************************************************************--*/s   211: 	   212: {i   213:     /*F   214:     ** Classify the source line just completed as either mixedQ   215:     ** statements/comments, statements only, comments only, or blank, andc@   216:     ** increment the appropriate source record counters.   217:     */   218:     /   219:     if (statement && comment) {Y)   220: 	inc_source_mixed(aSourceRecord);
   221:     }1    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);t
   230:     }    231:     B   232:     statement = 0;			    /* Reset counters for next	    */2   233:     comment   = 0;			    /* line.			    */   234: )   235:     new_list_line(aSourceRecord);A	   236: }N
MEND new_source_line. Go to: Beginning of routine.

<



r   237: V   238: /*************************************************************************++*/

bROUTINE iskeyword. Go to: mNext routine in file; Routines in this file.

E

    239: static int iskeyword( V   240: /* Determines whether or not an alphanumeric token is a source language	    */!   241: /* keyword.								    */   242: !   243:     char    *aKeywords[],E,   244: 	    /* (READ, BY ADDR):						    */O   245: 	    /* List of known source language keyword string pointers, in    */DE   246: 	    /* alphabetical order, terminated by NULL entry.		    */   247:    248:     char    *aToken,   249: 	    /* (READ, BY ADDR):						    */1   250: 	    /* Token string to check.					    */    251: 4   252: )	/* Returns status of comparison:				    *//   253: 	/*	1   - Token is a keyword.				    */E3   254: 	/*	0   - Token is not a keyword.				    */RO   255: 	/*****************************************************************--*/    256: 	   257: { ?   258:     int	    cmpstat;			    /* Comparison status.	    */I   259: b   260:     while (*aKeywords != NULL && (cmpstat = strcmp(*aKeywords++, aToken)) < 0);   261:     return !cmpstat;	   262: }E
GEND iskeyword. Go to: Beginning of routine.





A   263: V   264: /*************************************************************************++*/

dROUTINE evaluate_if. Go to: mNext routine in file; Routines in this file.

2

o   265: static int evaluate_if(tF   266: /* Evaluates a #if conditional compilation directive.			    */   267: /*									    */hB   268: /* WARNING: This is just a dummy version for now.			    */   269:    270:     char    *aCondition,-   271: 	    /* (READ, BY ADDR):  					    */1:   272: 	    /* Condition string to be evaluated.			    */   273: K   274: )	/* Returns boolean flag to indicate results of evaluation.	    */	O   275: 	/*****************************************************************--*/    276: 	   277: { I   278:     return atoi(aCondition);	/* Handle simple numeric constant */		   279: }
IEND evaluate_if. Go to: Beginning of routine.

;



    280: V   281: /*************************************************************************++*/

gROUTINE evaluate_ifdef. Go to: *mNext routine in file; Routines in this file.

.

0"   282: static int evaluate_ifdef(H   283: /* Evaluates a #ifdef conditional compilation directive.		    */   284: /*									    */LEND evaluate_ifdef. Go to: Beginning of routine.





f   297: V   298: /*************************************************************************++*/

bROUTINE get_token. Go to: mNext routine in file; Routines in this file.

r

r   299: static get_token(rV   300: /* Source file input scanner. Reads the next lexical token from the source  */A   301: /* file and accumulates source line statistics.				    */2   302: !   303:     FILE    *aSourceFile,p(   304: 		/* (READ, BY ADDR):					    */8   305: 		/* Source file containing C language.			    */   306:    307:     SOURCEFILE   308: 	    *aSourceRecord,*   309: 		/* (MODIFY, BY ADDR):					    */B   310: 		/* Source file information record. The line count	    */2   311: 		/* statistics will be updated.				    */   312:    313:     char    *aToken	)   314: 		/* (WRITE, BY ADDR):					    */	5   315: 		/* String buffer to receive token.			    */   316: J   317: )	/* Returns code indicating which type of token was found:	    */?   318: 	/*     END_C_SOURCE - End of the source file.			    */*8   319: 	/*     LPAREN	    - Left parenthesis.				    */8   320: 	/*     RPAREN	    - Right parenthesis.			    */2   321: 	/*     LBRACE	    - Left brace.				    */3   322: 	/*     RBRACE	    - Right brace.				    */R3   323: 	/*     SEMICOLON    - Semicolon.				    */>A   324: 	/*     IDENTIFIER   - Routine or data identifier		    */*:   325: 	/*     KEYWORD	    - C language keyword.			    */;   326: 	/*     MACBEGIN	    - Beginning of macro.			    */H1   327: 	/*     SPACE	    - Whitespace.				    */r>   328: 	/*     OTHER	    - Some other type of token.			    */O   329: 	/*****************************************************************--*/1   330: 	   331: {_:   332:     int	    ch;				    /* Input character.		    */E   333:     int	    quotelen;			    /* Length of quoted token.	    */t<   334:     c_scanner_states			    /* Scanner state.		    */    335: 	    state = FIND_START;K   336:     char    *nextchar = aToken;		    /* Pointer to next char	    */h.   337: 					    /* position in aToken.	    */I   338:     char    condbuf[256];		    /* Conditional directive buf.   */6@   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);n   346: 	switch (state) {a   347: 	case FIND_START:\   348: 	    list_char(ch); 9   349: 	    if (isalpha(ch) || ch == '_' || ch == '$') {"!   350: 		state = FIND_END_ALNUM;s   351: 		*nextchar++ = ch;0   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') {nH   361: 		    if (macro == IN_MACRO) {/* Special case: if end of line */A   362: 			macro = NO_MACRO;   /* in a macro, this is really   */0$   363: 			ungetc(ch, aSourceFile); A   364: 			return cond_token(RBRACE); /* end of a "routine"    */2,   365: 		    }			    /* definition.		    */   366: 		    else {*   367: 			new_source_line(aSourceRecord);   368: 		    }i   369: 		}c!   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 '}':c   387: 		    statement++;(   388: 		    return cond_token(RBRACE);   389: 		    break;   390: 		case ';':e   391: 		    statement++;+   392: 		    return cond_token(SEMICOLON);2   393: 		    break;   394: 		case '#':   395: 		    statement++;   396: 		    *nextchar++ = ch;c)   397: 		    state = FIND_END_DIRECTIVE;    398: 		    break;   399: 		case '"':c   400: 		    statement++;'   401: 		    state = FIND_END_DQUOTED;t   402: 		    quotelen = 0;o   403: 		    break;   404: 		case '\'':   405: 		    statement++;'   406: 		    state = FIND_END_SQUOTED;S   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: 		    }2   416: 		    else {#   417: 			ungetc(ch, aSourceFile);>   418: 			statement++;A   419: 		    }"   420: 		    break;   421: 		default:   422: 		    if (ch != EOF) {   423: 			*nextchar++ = ch;   424: 			*nextchar   = '\0';   425: 			statement++; $   426: 			return cond_token(OTHER);   427: 		    }/   428: 		}k   429: 	    }   430: 	    break;2   431: 	case FIND_END_ALNUM:9   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';2,   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';d#   457: 		return cond_token(OTHER);p   458: 	    }   459: 	    break;2   460: 	case FIND_END_SPACE:2   461: 	    if (isspace(ch)) {o   462: 		list_char(ch);   463: 		if (ch == '\n') {HH   464: 		    if (macro == IN_MACRO) {/* Special case: if end of line */A   465: 			macro = NO_MACRO;   /* in a macro, this is really   */>#   466: 			ungetc(ch, aSourceFile);0J   467: 			return cond_token(RBRACE);	    /* the end of a "routine"	    */,   468: 		    }			    /* definition.		    */   469: 		    else {*   470: 			new_source_line(aSourceRecord);   471: 		    }    472: 		}a   473: 	    }   474: 	    else {e"   475: 		ungetc(ch, aSourceFile);   476: 		*nextchar = '\0';i#   477: 		return cond_token(SPACE);    478: 	    }   479: 	    break;o!   480: 	case FIND_END_DIRECTIVE:    481: 	    if (isalpha(ch)) {    482: 		list_char(ch);   483: 		*nextchar++ = ch;    484: 		statement++;   485: 	    }   486: 	    else {a"   487: 		ungetc(ch, aSourceFile);   488: 		*nextchar = '\0';*+   489: 		if (!strcmp(aToken, "#define")) {    490: 		    macro = IN_MACRO;(*   491: 		    return cond_token(MACBEGIN);   492: 		}9,   493: 		else if (!strcmp(aToken, "#if")) {;   494: 		    fgets(condbuf, sizeof(condbuf), aSourceFile);2#   495: 		    if (list_enabled()) {*'   496: 			fputs(condbuf, list_file());*   497: 		    }R-   498: 		    new_source_line(aSourceRecord);=*   499: 		    copy = evaluate_if(condbuf);   500: 		    return SPACE;=   501: 		}N/   502: 		else if (!strcmp(aToken, "#ifdef")) {i;   503: 		    fgets(condbuf, sizeof(condbuf), aSourceFile);c#   504: 		    if (list_enabled()) {u'   505: 			fputs(condbuf, list_file());e   506: 		    } -   507: 		    new_source_line(aSourceRecord);h-   508: 		    copy = evaluate_ifdef(condbuf);    509: 		    return SPACE;a   510: 		} 0   511: 		else if (!strcmp(aToken, "#ifndef")) {;   512: 		    fgets(condbuf, sizeof(condbuf), aSourceFile);0#   513: 		    if (list_enabled()) { '   514: 			fputs(condbuf, list_file());/   515: 		    }*-   516: 		    new_source_line(aSourceRecord);*.   517: 		    copy = !evaluate_ifdef(condbuf);   518: 		    return SPACE;e   519: 		}o.   520: 		else if (!strcmp(aToken, "#else")) {   521: 		    copy = !copy;e   522: 		    return SPACE;H   523: 		} /   524: 		else if (!strcmp(aToken, "#endif")) {*   525: 		    copy = 1;*   526: 		    return SPACE;>   527: 		}0   528: 		else   529: 		{r'   530: 		    return cond_token(OTHER);e   531: 		}    532: 	    }   533: 	    break;n   534: 	case FIND_END_DQUOTED:t   535: 	    list_char(ch);l   536: 	    if (ch == '"') {t   537: 		statement++;#   538: 		return cond_token(OTHER);h   539: 	    }C   540: 	    else if (ch == '\\') {	    /* Check for escape seq. */    541: 		statement++;   542: 		quotelen++;I)   543: 	        ch = fgetc(aSourceFile);Y   544: 		list_char(ch);   545: 		statement++;   546: 		quotelen++;    547: 	    }#   548: 	    else if (ch == '\n') {S)   549: 		new_source_line(aSourceRecord);)   550: 	    }5   551: 	    else if (quotelen > MAX_DQUOTE_LEN) {n   552: 		printf(	O   553: 	    "WARNING: Suspected unterminated double quote at line %d of %s\n",F   554: 		    source_line(aSourceRecord), source_name(aSourceRecord));#   555: 		return cond_token(OTHER);   556: 	    }   557: 	    else {w   558: 		statement++;   559: 		quotelen++;/   560: 	    }   561: 	    break;e   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);5   575: 	    }C   576: 	    else if (ch == '\n' || quotelen > MAX_SQUOTE_LEN) {B)   577: 		new_source_line(aSourceRecord);    578: 		printf(sO   579: 	    "WARNING: Suspected unterminated single quote at line %d of %s\n",F   580: 		    source_line(aSourceRecord), source_name(aSourceRecord));#   581: 		return cond_token(OTHER);2   582: 	    }   583: 	    else {r   584: 		statement++;   585: 		quotelen++;	   586: 	    }   587: 	    break;t   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: 		}d   597: 		else {&   598: 		    ungetc(ch, aSourceFile);   599: 		    comment++;   600: 		}    601: 	    }#   602: 	    else if (ch == '\n') { )   603: 		new_source_line(aSourceRecord);t   604: 	    }   605: 	    else {A   606: 		comment++;   607: 	    }   608: 	    break;c
   609: 	}    610:     } while (ch != EOF);   611:     copy = 1;3    612:     return END_C_SOURCE;	   613: }a
GEND get_token. Go to: Beginning of routine.

1



+   614:     V   615: /*************************************************************************++*/

aROUTINE c_parser. Go to: fmNext routine in file; Routines in this file.

f

/"   616: language_element c_parser(U   617: /* Parses C source language statements, looking for routine definition	    */rT   618: /* begin and end, and routine references. Retrieves the next language	    */2   619: /* element in the source file.						    */   620: /*									    */ V   621: /* Note that this version is a very simple-minded parser, and has several   */U   622: /* limitations.  It is not able to identify function pointer usages as	    */+V   623: /* routine references. It may also be confused by other legal constructs.   */   624: !   625:     FILE    *aSourceFile,e(   626: 		/* (READ, BY ADDR):					    */H   627: 		/* Source file containing C language. Must be opened by	    */    628: 		/* caller.						    */   629:    630:     SOURCEFILE   631: 	    *aSourceRecord,(   632: 		/* (READ, BY ADDR):					    */5   633: 		/* Source file information record.			    */    634:    635:     char    *aElement,)   636: 		/* (WRITE, BY ADDR):					    */3H   637: 		/* String buffer that will receive the recognized source    */)   638: 		/* language element.					    */I   639:     640:     long    *aSourceLine)   641: 		/* (WRITE, BY ADDR):					    */	H   642: 		/* Buffer that will receive the line number of aElement.    */   643: N   644: )	/* Returns one of the following values indicating the type of	    */2   645: 	/* element output in aElement:					    */K   646: 	/*      PARSE_ERROR	    - An error was detected in the input    */4%   647: 	/*			      stream.				    */lH   648: 	/*	END_OF_SOURCE	    - The normal end of file was found.	    */J   649: 	/*	ROUTINE_DEF_BEGIN   - The beginning of a routine definition */'   650: 	/*			      was found.			    */ G   651: 	/*	ROUTINE_DEF_END	    - The end of the current routine	    */!1   652: 	/*			      definition was found.		    */*F   653: 	/*	ROUTINE_REF	    - A routine reference (call) was found. */O   654: 	/*****************************************************************--*/   655: 	   656: {D@   657:     static c_parser_states		    /* Parser state.		    */    658: 	    state = FIND_IDENT;<   659:     static int				    /* Nested braces level.	    */   660: 	    blevel;A   661:     static char				    /* Name of current routine.	    */2.   662: 	    curdefname[MAX_ROUTINE_NAME + 1];D   663:     int	    plevel;			    /* Nested parenthesis level.    */?   664:     c_token_types			    /* Type of source token.	    */   665: 	    tokentype; R   666:     char    token[MAX_ROUTINE_NAME + 1];    /* Source token buffer.	    */   667:    668:     /*R   669:     ** This function operates as a state machine. The states represent theW   670:     ** various tokens expected next in the token stream, according to C syntax._W   671:     ** Whenever a routine definition beginning or end, or routine reference, is4P   672:     ** recognized, the parser returns to the caller. However, context isQ   673:     ** maintained between calls to the parser via static state variables.5   674:     */   675:    676:     do {B   677: 	tokentype = get_token(aSourceFile, aSourceRecord, token);   678: 	switch (state) {    679: 	case FIND_IDENT:	+   680: 	    if (tokentype == IDENTIFIER) {	"   681: 		strcpy(aElement, token);4   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;e   689: 	case FIND_DEF_LPAREN:'   690: 	    if (tokentype == LPAREN) { )   691: 		change_pstate(FIND_DEF_RPAREN);c   692: 		paren_level_zero();n   693: 	    }0   694: 	    else if (tokentype == IDENTIFIER) {"   695: 		strcpy(aElement, token);4   696: 		*aSourceLine = source_line(aSourceRecord);   697: 	    }+   698: 	    else if (tokentype != SPACE) {o$   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 {6   708: 		    change_pstate(FIND_LBRACE_OR_SEMICOLON);   709: 		}_   710: 	    },   711: 	    else if (tokentype == LPAREN) {   712: 		paren_level_inc();   713: 	    }   714: 	    break;o'   715: 	case FIND_LBRACE_OR_SEMICOLON: '   716: 	    if (tokentype == LBRACE) {5$   717: 		change_pstate(IN_ROUTINE);   718: 		block_level_zero();e$   719: 		strcpy(curdefname, token);#   720: 		return ROUTINE_DEF_BEGIN;)0   721: 	    }					/* Forward or external	    */G   722: 	    else if (tokentype == SEMICOLON) {	/* declaration.		    */u$   723: 		change_pstate(FIND_IDENT);   724: 	    }J   725: 	    else if (tokentype != SPACE) {	/* Parameter declarations.  */%   726: 		change_pstate(FIND_LBRACE);c   727: 	    }   728: 	    break;l   729: 	case FIND_LBRACE:G   730: 	    if (tokentype == LBRACE) {		/* Keep grabbing tokens	    */"@   731: 		change_pstate(IN_ROUTINE);	/* until left brace.	    */   732: 		block_level_zero();l$   733: 		strcpy(curdefname, token);#   734: 		return ROUTINE_DEF_BEGIN;    735: 	    }
   736: #if 0+   737: 	    else if (tokentype != SPACE) {e$   738: 		change_pstate(FIND_IDENT);   739: 	    }   740: #endif   741: 	    break;    742: 	case FIND_MACRO_IDENT:l+   743: 	    if (tokentype == IDENTIFIER) {t"   744: 		strcpy(aElement, token);4   745: 		*aSourceLine = source_line(aSourceRecord);+   746: 		change_pstate(FIND_MACRO_LPAREN);c   747: 	    }+   748: 	    else if (tokentype != SPACE) {$   749: 		change_pstate(FIND_IDENT);   750: 	    }   751: 	    break;5    752: 	case FIND_MACRO_LPAREN:'   753: 	    if (tokentype == LPAREN) { $   754: 		change_pstate(IN_ROUTINE);$   755: 		strcpy(curdefname, token);#   756: 		return ROUTINE_DEF_BEGIN;t   757: 	    }:   758: 	    else {			    /* Cannot tolerate SPACE here */$   759: 		change_pstate(FIND_IDENT);   760: 	    }   761: 	    break;S   762: 	case IN_ROUTINE:S'   763: 	    if (tokentype == LBRACE) {e   764: 		block_level_inc();   765: 	    },   766: 	    else if (tokentype == RBRACE) {   767: 		if (blevel == 0) {!   768: 		    trace_blmsg(BLEND);D(   769: 		    change_pstate(FIND_IDENT);8   770: 		    *aSourceLine = source_line(aSourceRecord);+   771: 		    strcpy(aElement, curdefname);7%   772: 		    return ROUTINE_DEF_END;t   773: 		}    774: 		else {    775: 		    block_level_dec();   776: 		}e   777: 	    }0   778: 	    else if (tokentype == IDENTIFIER) {"   779: 		strcpy(aElement, token);4   780: 		*aSourceLine = source_line(aSourceRecord);)   781: 		change_pstate(FIND_REF_LPAREN);R   782: 	    }2   783: 	    else if (tokentype == END_C_SOURCE) {6   784: 		printf("ERROR: Unexpected end of file %s\n",*   785: 		    source_name(aSourceRecord));   786: 		return PARSE_ERROR;n   787: 	    }   788: 	    break;   789: 	case FIND_REF_LPAREN:&   790: 	    if (tokentype != SPACE) {$   791: 		change_pstate(IN_ROUTINE);$   792: 		if (tokentype == RBRACE) {3   793: 					    /* Must be scanner finding end  */;3   794: 					    /* of macro, calling it rbrace. */hG   795: 		    if (blevel == 0) {	    /* Treat as end of routine.	    */T   796: 			trace_blmsg( J   797: 		    "\nTRACE: brace level already 0 (assuming end of macro)\n");%   798: 			change_pstate(FIND_IDENT);	5   799: 			*aSourceLine = source_line(aSourceRecord); (   800: 			strcpy(aElement, curdefname);"   801: 			return ROUTINE_DEF_END;   802: 		    }o7   803: 		    else {		    /* Must be end of data	    */}:   804: 			block_level_dec();  /* initializer list.	    */?   805: 			trace_blmsg("(assuming end of data initializer)\n");e   806: 		    }=   807: 		}B   808: 	    }'   809: 	    if (tokentype == LPAREN) {   810: 		return ROUTINE_REF;*   811: 	    }   812: 	    break;*
   813: 	}0   814:     } while (tokentype != END_C_SOURCE);&   815:     change_pstate(FIND_IDENT);!   816:     return END_OF_SOURCE;=	   817: }"
FEND c_parser. Go to: Beginning of routine.





P
END OF FILEa!TOTAL: 10 routines, 67 Avg Lengthe

LGo to: Contents; Previous section; Beginning of section; Next file in section; Previous file in section.