316 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			316 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <stdio.h>
 | |
| #include <ctype.h>
 | |
| #include "states.h"
 | |
| 
 | |
| 
 | |
| #define is_letter( c)	   ( isalpha( c) || isdigit( c) || c == '_')
 | |
| #define save_or_put(c)	   if(previous_state==TEXT)putchar(c);else *bufptr++=c
 | |
| 
 | |
| 
 | |
| 
 | |
| /* This program processes the file 'as.c', and will take care of things like
 | |
|  * %d( <expression>), @func( arg), %$(   ), etc.
 | |
|  * The main-loop is constructed as a finite automat.
 | |
|  */
 | |
| 
 | |
| 
 | |
| main()
 | |
| {
 | |
| 	char buffer[256], *bufptr = buffer;
 | |
| 	int c, state = TEXT, previous_state = TEXT, depth = 0;
 | |
| 
 | |
| 	pr_header();
 | |
| 	while ( ( c = getchar()) != EOF)
 | |
| 		switch ( state) {
 | |
| 		  case TEXT :
 | |
| 				switch ( c) {
 | |
| 				  case '/' : state = SLASH;
 | |
| 					     previous_state = TEXT;
 | |
| 					     save_or_put( c);
 | |
| 					     break;
 | |
| 				  case '"' : state = STRING;
 | |
| 					     previous_state = TEXT;
 | |
| 					     save_or_put( c);
 | |
| 					     break;
 | |
| 				  case '\'': state = CHAR_CONST;
 | |
| 					     previous_state = TEXT;
 | |
| 					     save_or_put( c);
 | |
| 					     break;
 | |
| 				  case '@' : state = AT;
 | |
| 					     break;
 | |
| 				  default  : putchar( c);
 | |
| 					     break;
 | |
| 			      	}
 | |
| 			      	break;
 | |
| 
 | |
| 
 | |
| 		  case SLASH :
 | |
| 				state =  ( c == '*' ? COMMENT : TEXT);
 | |
| 			      	save_or_put( c);
 | |
| 			      	break;
 | |
| 		  case COMMENT :
 | |
| 				if ( c == '*')
 | |
| 					state = STAR;
 | |
| 			      	save_or_put( c);
 | |
| 			      	break;
 | |
| 		  case STAR :
 | |
| 				if ( c == '/')
 | |
| 					state = previous_state;	
 | |
| 				else if ( c != '*')
 | |
| 					state = COMMENT;
 | |
| 			      	save_or_put( c);
 | |
| 			      	break;
 | |
| 
 | |
| 
 | |
| 
 | |
| 		  case STRING :
 | |
| 				if ( c == '"')
 | |
| 					state = previous_state;
 | |
| 				else if ( c == '\\')
 | |
| 					state = BACKSLASH_in_STRING;
 | |
| 				save_or_put( c);
 | |
| 				break;
 | |
| 
 | |
| 		  case BACKSLASH_in_STRING :
 | |
| 				state = STRING;
 | |
| 				save_or_put( c);
 | |
| 				break;
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 		  case CHAR_CONST :
 | |
| 				if ( c == '\'')
 | |
| 					state = previous_state;
 | |
| 				else if ( c == '\\')
 | |
| 					state = BACKSLASH_in_CHAR_CONST;
 | |
| 				save_or_put( c);
 | |
| 				break;
 | |
| 
 | |
| 		  case BACKSLASH_in_CHAR_CONST :
 | |
| 				state = CHAR_CONST;
 | |
| 				save_or_put( c);
 | |
| 				break;
 | |
| 
 | |
| 				
 | |
| 				
 | |
| 		  case AT :	/* @if '(' <CONDITION> ')'
 | |
| 				 * @elsif '(' <CONDITION> ')'
 | |
| 				 * @else
 | |
| 				 * @fi
 | |
| 				 * @<IDENTIFIER> '(' <PARAM_LIST> ')'
 | |
| 				 */
 | |
| 				if ( is_letter( c))
 | |
| 					*bufptr++ = c;
 | |
| 				else {
 | |
| 					ungetc( c, stdin);
 | |
| 					state = WHITE_SPACE;
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 		  case WHITE_SPACE :
 | |
|  				if ( isspace( c))
 | |
| 					*bufptr++ = c;
 | |
| 				else if ( c == '(') {
 | |
| 					*bufptr++ = c;
 | |
| 					depth = 1;
 | |
| 					state = CAL_or_QUEST;
 | |
| 				}
 | |
| 				else {
 | |
| 					*bufptr = '\0';
 | |
| 					pr_ELSE_or_FI( buffer);
 | |
| 					bufptr = buffer;
 | |
| 					ungetc( c, stdin);
 | |
| 					state = TEXT;
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 		  case CAL_or_QUEST :	/* match ')' */
 | |
| 				*bufptr++ =c;
 | |
| 				switch ( c) {
 | |
| 				  case '(' : depth++;
 | |
| 					     break;
 | |
| 				  case ')' : depth--;
 | |
| 					     if ( depth == 0) {
 | |
| 						     *bufptr = '\0';
 | |
| 						     pr_CALL_or_QUEST( buffer);
 | |
| 						     bufptr = buffer;
 | |
| 						     state = TEXT;
 | |
| 					     }
 | |
| 					     break;
 | |
| 				  case '/' : state = SLASH;
 | |
| 					     previous_state = CAL_or_QUEST;
 | |
| 					     break;
 | |
| 				  case '"' : state = STRING;
 | |
| 					     previous_state = CAL_or_QUEST;
 | |
| 					     break;
 | |
| 				  case '\'': state = CHAR_CONST;
 | |
| 					     previous_state = CAL_or_QUEST;
 | |
| 					     break;
 | |
| 				}
 | |
| 				break;
 | |
| 		  default :	
 | |
| 				fprintf( stderr, "Unknown state : %d\n", state);
 | |
| 				break;
 | |
| 	}
 | |
| 	exit( 0);
 | |
| }
 | |
| 
 | |
| pr_header()
 | |
| {
 | |
| 	printf( "#include \"as_parser.h\"\n");
 | |
| 	printf( "#line 1 \"as.c\"\n");
 | |
| }
 | |
| 
 | |
| 
 | |
| pr_ELSE_or_FI( str)
 | |
| char *str;
 | |
| {
 | |
| 	if ( strncmp( str, "else", 4) == 0)
 | |
| 		printf( "fprint( outfile, \"}\else {\");%s", str+4);
 | |
| 	else if ( strncmp( str, "fi", 2) == 0)
 | |
| 		printf( "fprint( outfile, \"}\");%s", str+2);
 | |
| 	else
 | |
| 		fprintf( stderr, "%s  unexpected!!\n", str);
 | |
| }
 | |
| 
 | |
| 
 | |
| pr_CALL_or_QUEST( str)
 | |
| char *str;
 | |
| {
 | |
| 	if ( strncmp( str, "if", 2) == 0 && !(is_letter( *(str+2))))
 | |
| 		pr_if( str);
 | |
| 	else if ( strncmp( str, "elsif", 5) == 0 && !(is_letter( *(str+5))))
 | |
| 		pr_elsif( str);
 | |
| 	else
 | |
| 		pr_call( str);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Adjust 'cur_pos' when necessary */
 | |
| 
 | |
| pr_call( call)
 | |
| char *call;
 | |
| {
 | |
| 	if ( strncmp( "text", call, 4) == 0 && isdigit( *(call+4))) 
 | |
| 		printf( "cur_pos += %d;", *(call+4) - '0');
 | |
| 	else if ( strncmp( "reloc", call, 5) == 0 && isdigit( *(call+5)))
 | |
| 		printf( "cur_pos += %d;", *(call+5) - '0');
 | |
| 
 | |
| 	pr_text_with_conversions( call);
 | |
| 	printf( "fprint( outfile, \";\")");
 | |
| }
 | |
| 
 | |
| pr_elsif( quest)
 | |
| char *quest;
 | |
| {
 | |
| 	printf( "fprint( outfile, \"}\else if\");");
 | |
| 	pr_text_with_conversions( quest+5);
 | |
| 	printf( "fprint( outfile, \"{\");");
 | |
| }
 | |
| 
 | |
| pr_if( quest)
 | |
| char *quest;
 | |
| {
 | |
| 	pr_text_with_conversions( quest);
 | |
| 	printf( "fprint( outfile, \"{\");");
 | |
| }
 | |
| 
 | |
| 
 | |
| pr_text_with_conversions( str)
 | |
| char *str;
 | |
| {
 | |
| 	char *ptr, *next_conversion(), *pr_conversion();
 | |
| 
 | |
|         while (  ptr = next_conversion( str)) {
 | |
| 		/* ptr points to '%'-sign */
 | |
| 	 	*ptr = '\0';
 | |
| 		printf( "fprint( outfile, \"%s\");", str);
 | |
| 	 	*ptr = '%';
 | |
| 	        str = pr_conversion( ptr);
 | |
| 	}
 | |
| 	printf( "fprint( outfile, \"%s\");", str);
 | |
| }
 | |
| 
 | |
| char *next_conversion( str)
 | |
| char *str;
 | |
| {
 | |
| 	char *match();
 | |
| 
 | |
| 	while ( *str && *str != '%') {
 | |
| 		switch ( *str++) {
 | |
| 		  case '\'' : str = match( '\'', str) + 1;
 | |
| 			      break;
 | |
| 		  case '"'  : str = match( '"', str) + 1;
 | |
| 			      break;
 | |
| 		}
 | |
| 	}
 | |
| 	return( *str == '%' ? str : (char *)0);
 | |
| }
 | |
| 
 | |
| char *match( c, str)
 | |
| char c, *str;
 | |
| {
 | |
| 	while ( *str && ( *str != c || *(str-1) == '\\'))
 | |
| 		str++;
 | |
| 	return( *str ? str : str-1);
 | |
| }
 | |
| 
 | |
| char *match_bracket( str)
 | |
| char *str;
 | |
| 
 | |
| /* find ')', but look at nesting '('-')' pairs, return position of ')'.
 | |
|  */
 | |
| {
 | |
| 	int depth;
 | |
| 	char *match();
 | |
| 
 | |
| 	depth = 1;
 | |
| 	while ( *str && depth != 0) { 
 | |
| 		switch ( *str++) {
 | |
| 		  case '\'' : str = match( '\'', str+1) + 1;
 | |
| 			      break;
 | |
| 		  case '"'  : str = match( '"', str+1) + 1;
 | |
| 			      break;
 | |
| 		  case '('  : depth++;
 | |
| 			      break;
 | |
| 		  case ')'  : depth--;
 | |
| 			      break;
 | |
| 		}
 | |
| 	}
 | |
| 	return( str-1);
 | |
| }
 | |
| 
 | |
| 
 | |
| char *find( c, str)
 | |
| char c, *str;
 | |
| {
 | |
| 	while ( *str && *str != c)
 | |
| 		str++;
 | |
| 	return( str);
 | |
| }
 | |
| 	
 | |
| char *pr_conversion( str)
 | |
| char *str;
 | |
| 
 | |
| /* str points to '%'-sign, returns pointer to first character AFTER the
 | |
|  * conversion
 | |
|  */
 | |
| {
 | |
| 	char *start, *ptr, *match_bracket(), *find();
 | |
| 
 | |
| 	start = find( '(', str+1);
 | |
|  	*start++ = '\0';
 | |
| 
 | |
| 	ptr = match_bracket( start);
 | |
| 	*ptr = '\0';
 | |
| 
 | |
| 	if ( *(str+1) == '$')
 | |
| 		printf( "eval( %s);", start);
 | |
| 	else if ( strncmp( str+1, "dist", 4) == 0)
 | |
| 		printf( "dist( %s);", start);
 | |
| 	else
 | |
| 		printf( "fprint( outfile, \"%%%s\", %s);", str+1, start);
 | |
| 
 | |
| 	return( ptr+1);
 | |
| }
 |