ack/util/ceg/as_parser/eval/eval.c

347 lines
6.5 KiB
C

#include <stdlib.h>
#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;
{
char c;
printf( "{");
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, \";\");");
printf( "}");
for (; ( c = getchar()) != ';' ; putchar( c)); /* skip ';' */
}
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, \"");
pr_string( str);
printf( "\");");
*ptr = '%';
str = pr_conversion( ptr);
}
printf( "fprint( outfile, \"");
pr_string( str);
printf( "\");");
}
pr_string( s)
char *s;
{
for ( ; *s != '\0'; s++)
switch ( *s) {
case '"' : printf( "\\\"");
break;
case '\\': printf( "\\\\");
break;
case '\n': printf( "\\n");
break;
default : printf( "%c", *s);
}
}
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);
}