#include #include #include "defs.h" #include "types.h" #include "exports.h" #include "file.h" #include "ciflex.h" #define MAXARGS 10 /* for user-extensions */ #define TOPINT INT_MAX / 10 typedef enum { EOFILE, BLANK, SPACES, OCOMM, CCOMM, LETTER, DIGIT, SEMI, SIGN, NEWLINE } CifLexType; private char *cifFile; /* input file name */ private File fin; /* input file descriptor */ private int nLine; /* line number in input file */ private int inLayer; /* flag = 1 when scanning layer name */ private CifLexType *cifChars; /* lexical character's table */ public int currNum; /* number returned by lexer */ public char *tokens[ MAXARGS+1 ]; /* tokens in user-extension */ public int cifErrs; /* lexical error counter */ /* * Return the next token. Skip through comments. * Group digits into numbers and set 'currNum' to it, as a side effect. */ char GetToken() { char c; static int sign = 1; register int num; for(;;) { GetChar( c, fin ); switch( cifChars[ c ] ) { case LETTER : case DIGIT : case SEMI : case SIGN : case OCOMM : return( c ); break; case EOFILE : return( EO_FILE ); break; case NEWLINE : nLine++; break; case SPACES : case BLANK : break; case CCOMM : LexError( "Unmatched ')' (ignored)", RECOVER ); break; default : LexError( "Unknown character in input", FATAL ); } } } /* * Pass over a comment command */ public void PassComment() { int commLevel; char c; commLevel = 1; while( commLevel > 0 ) { GetChar( c, fin ); switch( cifChars[ c ] ) { case OCOMM : commLevel++; break; case CCOMM : commLevel--; break; case EOFILE : LexError( "Non Terminated Comment", FATAL ); break; case NEWLINE : nLine++; break; default : ; } } } /* * Parse the layer name. Return the next character in the stream. */ public void GetLayerName( name ) char name[]; { int i; char c; i = 0; inLayer = TRUE; c = GetToken(); while( ( i < 4 ) and (cifChars[ c ] == DIGIT or cifChars[ c ] == LETTER) ) { name[ i++ ] = c; GetChar(c, fin); } name[ i ] = '\0'; inLayer = FALSE; UngetChar(fin); } /* * Skip the input file until a ';' is encountered (or an end of file). */ char CifSkip() { char c; do { GetChar( c, fin ); if (c == '\n') nLine++; } while( c != ';' and c != '\0' ); return( c ); } /* * Parse the next command (ended with ';') into an argument list (a la unix). * Return the number of arguments actually found. */ int ParseUserArgs() { static char argBuff[ 512 ]; register char *sp, c; register int nargs; nargs = 0; *tokens = sp = argBuff; for(;;) { GetChar( c, fin ); switch( cifChars[ c ] ) { case NEWLINE : nLine++; case SPACES : if( sp > tokens[ nargs ] ) { *sp++ = '\0'; tokens[ ++nargs ] = sp; if( nargs == MAXARGS ) { LexError( "Too many User Extension arguments",RECOVER); CifSkip(); return 0; } } break; case SEMI : case EOFILE : if( sp > tokens[ nargs ] ) nargs++; *sp++ = '\0'; *sp = c; tokens[ nargs ] = sp; return( nargs ); default : *sp++ = c; } } } /* * Print an error message, followed by the line in which the error was detected * If the 'err' is set to FATAL, then the program exists immediatly. */ LexError( msg, err ) char *msg; LexErrorType err; { int col; fprintf( stderr, "Error in \"%s\": line %d: %s\n", cifFile, nLine, msg ); col = PrintErrLine( &fin ); while( --col > 0 ) fputc( '-', stderr ); fputs( "^\n", stderr ); if( err == FATAL ) Crash( "Fatal Error encountered: no output created\n", 1 ); if( cifErrs++ > 500 ) Crash( "Too many errors...abort\n", 1 ); } /* * Initialize the lexer state: character tables, line counter, error count ... */ int InitLexer( fname, buffAdr, charBuff ) char *fname; char *buffAdr; CifLexType *charBuff; { register unsigned char c; cifChars = charBuff; for( c = '\0'; c <= ' '; c++ ) cifChars[ c ] = SPACES; for( c = 0x21; c != 255; c++ ) cifChars[ c ] = BLANK; for( c = '0'; c <= '9'; c++ ) cifChars[ c ] = DIGIT; for( c = 'A'; c < 'Z'; c++ ) cifChars[ c ] = LETTER; cifChars[ '(' ] = OCOMM; cifChars[ ')' ] = CCOMM; cifChars[ ';' ] = SEMI; cifChars[ '-' ] = SIGN; cifChars[ '\n' ] = NEWLINE; cifChars[ ENDOFFILE ] = EOFILE; cifFile = fname; inLayer = FALSE; nLine = 1; cifErrs = 0; return( OpenFile( fname, buffAdr, &fin ) ); } /* get a number according to CIF spec {sep}{"-"}integerD. */ int GetNumber(last) char last; { char c; int num, sign, type; sign = 1; type = LETTER; if (last != 0) { type = cifChars[last]; c = last; } while (type == LETTER) { c = GetToken(); type = cifChars[c]; } if ((type != DIGIT) && (type != SIGN)) LexError( "Number Expected", RECOVER ); num = 0; if(cifChars[c] == SIGN) { sign = -1; GetChar(c, fin); if (cifChars[c] != DIGIT) LexError( "Floating minus sign--making zero", RECOVER ); } while ( cifChars[c] == DIGIT) { if ( num >= TOPINT ) { LexError( "Number overflows maximum integer size", RECOVER); GetChar(c, fin); break; } else num = num * 10 + c - '0'; GetChar(c, fin); } num *= sign; UngetChar(fin); return num; }