cparser.c Source Code

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

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_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.