diff options
author | Andrey Nazarov <skuller@skuller.net> | 2007-08-14 20:18:08 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2007-08-14 20:18:08 +0000 |
commit | f294db4ccf45f6274e65260dd6f9a2c5faa94313 (patch) | |
tree | e8cf1ba2bfe9c8417eec17faf912442f52fc4ef2 /source/q_lex.c |
Initial import of the new Q2PRO tree.
Diffstat (limited to 'source/q_lex.c')
-rw-r--r-- | source/q_lex.c | 680 |
1 files changed, 680 insertions, 0 deletions
diff --git a/source/q_lex.c b/source/q_lex.c new file mode 100644 index 0000000..da363e6 --- /dev/null +++ b/source/q_lex.c @@ -0,0 +1,680 @@ +/* +Copyright (C) 2003-2006 Andrey Nazarov + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// +// lex.c +// + +#include "config.h" +#include <setjmp.h> +#include "q_shared.h" +#include "com_public.h" +#include "q_list.h" +#include "q_lex.h" + +lexContext_t lex; + +lexImm_t lex_immediate; +lexImmType_t lex_immediateType; + +jmp_buf lex_jmpbuf; + +static char *lex_punctuation[] = { "&&", "||", "<=", ">=","==", "!=", "+=", "-=", + "*=", "/=", "|=", "&=", "^=", "++", "--", "(*", + ";", ",", "!", "*", "/", "(", ")", "-", + "+", "=", "[", "]", "{", "}", ".", "<", + ">", "#", "&", "$", "|", "~", "^", "%", ":", NULL }; + + +void Lex_Error( const char *fmt, ... ) { + va_list argptr; + char buffer[MAXPRINTMSG]; + + va_start( argptr, fmt ); + Q_vsnprintf( buffer, sizeof( buffer ), fmt, argptr ); + va_end( argptr ); + + Com_Printf( "*************\n" ); + Com_Printf( "ERROR: line %i: %s\n", lex.currentLine, buffer ); + Com_Printf( "*************\n" ); + + longjmp( lex_jmpbuf, -1 ); +} + +/* +=============== +Lex_NewLine +=============== +*/ +void Lex_NewLine( void ) { + if( lex.rejectNewLines ) { + Lex_Error( "No newlines expected" ); + } + lex.currentLine++; +} + +/* +=============== +Lex_Whitespace +=============== +*/ +static void Lex_Whitespace( void ) { + while( 1 ) { + while( *lex.data <= ' ' ) { + if( !lex.data[0] ) { + return; + } + if( *lex.data == '\n' ) { + Lex_NewLine(); + } + lex.data++; + } + + if( lex.data[0] == '/' && lex.data[1] == '/' ) { + lex.data += 2; + while( *lex.data ) { + if( *lex.data == '\n' ) { + lex.data++; + Lex_NewLine(); + break; + } + lex.data++; + } + if( !lex.data[0] ) { + return; + } + continue; + } + + if( lex.data[0] == '/' && lex.data[1] == '*' ) { + lex.data += 2; + while( *lex.data ) { + if( *lex.data == '\n' ) { + Lex_NewLine(); + } else if( lex.data[0] == '*' && lex.data[1] == '/' ) { + lex.data += 2; + break; + } + lex.data++; + } + if( !lex.data[0] ) { + return; + } + continue; + } + + break; + } + +} + + +/* +=============== +Lex_String +=============== +*/ +static void Lex_String( void ) { + int c; + int stringLength; + int integer; + + lex.token[0] = 0; + lex.tokenLength = 0; + lex.tokenType = TT_IMMEDIATE; + lex_immediateType = IT_STRING; + lex_immediate.string[0] = 0; + stringLength = 0; + + while( 1 ) { + lex.data++; + + while( 1 ) { + c = *lex.data++; + + if( c == '\"' ) { + break; + } + + switch( c ) { + case '\0': + Lex_Error( "EOF inside quoted string" ); + break; + case '\n': + Lex_Error( "Newline inside quoted string" ); + break; + case '\\': + c = *lex.data++; + + switch( c ) { + case '\0': + Lex_Error( "EOF inside quoted string" ); + break; + case '\n': + Lex_Error( "Newline inside quoted string" ); + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'b': + c = '\b'; + break; + case '\"': + c = '\"'; + break; + case '\\': + c = '\\'; + break; + //case '\n': + // break; + case 'x': + integer = 0; + while( 1 ) { + c = *lex.data; + + if( c >= '0' && c <= '9' ) { + c = ( c - '0' ); + } else if( c >= 'a' && c <= 'f' ) { + c = ( c - 'a' ) + 10; + } else if( c >= 'A' && c <= 'F' ) { + c = ( c - 'A' ) + 10; + } else { + break; + } + + integer = ( integer << 4 ) + c; + + lex.data++; + } + if( integer > 0xff ) { + Lex_Error( "\\x%x does not fit in a character", integer ); + } + c = integer; + break; + default: + Lex_Error( "Unrecognized escape char" ); + break; + } + break; + default: + break; + } + + if( stringLength == MAX_STRING_CHARS - 1 ) { + Lex_Error( "String exceeded %i chars", MAX_STRING_CHARS ); + } + lex_immediate.string[stringLength++] = c; + + } + + lex_immediate.string[stringLength] = 0; + Lex_Whitespace(); + + c = *lex.data; + if( c != '\"' ) { + break; + } + } +} + +/* +=============== +Lex_Punctuation +=============== +*/ +static void Lex_Punctuation( void ) { + char **p; + int len = 0; + + for( p = lex_punctuation; *p; p++ ) { + len = strlen( *p ); + if( !strncmp( lex.data, *p, len ) ) { + break; + } + } + + if( !p[0] ) { + Lex_Error( "Unknown punctuation" ); + } + + lex.data += len; + strcpy( lex.token, *p ); + lex.tokenLength = len; + lex.tokenType = TT_PUNCTUATION; +} + +/* +=============== +Lex_Name +=============== +*/ +static void Lex_Name( void ) { + int c; + + lex.token[0] = 0; + lex.tokenLength = 0; + lex.tokenType = TT_NAME; + + c = *lex.data++; + while( 1 ) { + if( lex.tokenLength == MAX_TOKEN_CHARS - 1 ) { + Lex_Error( "Name exceeded %i chars", MAX_TOKEN_CHARS ); + } + lex.token[lex.tokenLength++] = c; + + c = *lex.data; + if( ( c < 'A' || c > 'Z' ) && ( c < 'a' || c > 'z' ) && ( c < '0' || c > '9' ) && c != '_' ) { + break; + } + + lex.data++; + } + + lex.token[lex.tokenLength] = 0; + +} + + +/* +=============== +Lex_VectorToken +=============== +*/ +#define MAX_VECTOR_TOKEN 32 + +char *Lex_VectorToken( void ) { + static char token[MAX_VECTOR_TOKEN]; + int tokenLength; + int c; + + token[0] = 0; + tokenLength = 0; + + Lex_Whitespace(); + + c = *lex.data++; + if( c == '\'' ) { + return NULL; + } + + while( 1 ) { + + if( ( c < '0' || c > '9' ) && c != '.' && c != '-' ) { + Lex_Error( "Illegal char inside vector" ); + } + if( tokenLength == MAX_VECTOR_TOKEN - 1 ) { + Lex_Error( "Vector component exceeded %i chars", MAX_VECTOR_TOKEN ); + } + token[tokenLength++] = c; + + c = *lex.data; + if( c <= ' ' || c == '\'' ) { + break; + } + + lex.data++; + } + + token[tokenLength] = 0; + + return token; +} + + +/* +=============== +Lex_Vector +=============== +*/ +static void Lex_Vector( void ) { + char *token; + vec4_t vector; + int numComponents; + + lex.token[0] = 0; + lex.tokenLength = 0; + lex.tokenType = TT_IMMEDIATE; + + lex.data++; + lex.rejectNewLines = qtrue; + + numComponents = 0; + while( 1 ) { + if( !( token = Lex_VectorToken() ) ) { + break; + } + + if( numComponents == 4 ) { + Lex_Error( "Too many vector components" ); + } + + vector[numComponents++] = atof( token ); + + } + + lex.rejectNewLines = qfalse; + + switch( numComponents ) { + case 0: + Lex_Error( "Empty vectors not allowed" ); + break; + case 1: + lex_immediate.vector[0] = vector[0]; + lex_immediate.vector[1] = 0; + lex_immediate.vector[2] = 0; + lex_immediate.vector[3] = 0; + lex_immediateType = IT_VECTOR1; + break; + case 2: + lex_immediate.vector[0] = vector[0]; + lex_immediate.vector[1] = vector[1]; + lex_immediate.vector[2] = 0; + lex_immediate.vector[3] = 0; + lex_immediateType = IT_VECTOR2; + break; + case 3: + lex_immediate.vector[0] = vector[0]; + lex_immediate.vector[1] = vector[1]; + lex_immediate.vector[2] = vector[2]; + lex_immediate.vector[3] = 0; + lex_immediateType = IT_VECTOR3; + break; + case 4: + lex_immediate.vector[0] = vector[0]; + lex_immediate.vector[1] = vector[1]; + lex_immediate.vector[2] = vector[2]; + lex_immediate.vector[3] = vector[3]; + lex_immediateType = IT_VECTOR4; + break; + } + +} + +/* +=============== +Lex_Number +=============== +*/ +static void Lex_Number( void ) { + int c; + int integer; + double value, frac; + + lex.token[0] = 0; + lex.tokenLength = 0; + lex.tokenType = TT_IMMEDIATE; + + integer = 0; + value = 0; + + c = *lex.data++; + if( c == '0' ) { + c = *lex.data++; + + switch( c ) { + case '\0': + Lex_Error( "EOF inside number" ); + break; + case '.': + frac = 0.1; + while( 1 ) { + c = *lex.data; + + if( c < '0' || c > '9' ) { + break; + } + + value += frac * ( c - '0' ); + frac *= 0.1; + + lex.data++; + } + lex_immediateType = IT_FLOAT; + lex_immediate.value = value; + return; + case 'x': + while( 1 ) { + c = *lex.data; + + if( c >= '0' && c <= '9' ) { + c = ( c - '0' ); + } else if( c >= 'a' && c <= 'f' ) { + c = ( c - 'a' ) + 10; + } else if( c >= 'A' && c <= 'F' ) { + c = ( c - 'A' ) + 10; + } else { + break; + } + + integer = ( integer << 4 ) + c; + + lex.data++; + } + lex_immediateType = IT_INT; + lex_immediate.integer = integer; + return; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + while( 1 ) { + integer = ( integer * 8 ) + ( c - '0' ); + + c = *lex.data; + + if( c < '0' || c > '9' ) { + break; + } + + if( c == 8 || c == 9 ) { + Lex_Error( "Bad octal digit" ); + } + + lex.data++; + } + lex_immediateType = IT_INT; + lex_immediate.integer = integer; + return; + + + case '0': + case '8': + case '9': + Lex_Error( "Bad octal digit" ); + break; + default: + lex.data--; + break; + } + + lex_immediateType = IT_INT; + lex_immediate.integer = 0; + return; + } + + + while( 1 ) { + integer = ( integer * 10 ) + ( c - '0' ); + + c = *lex.data; + if( c == '.' ) { + lex.data++; + + frac = 0.1; + value = integer; + while( 1 ) { + c = *lex.data; + + if( c < '0' || c > '9' ) { + break; + } + + value += frac * ( c - '0' ); + + frac *= 0.1; + lex.data++; + } + + lex_immediateType = IT_FLOAT; + lex_immediate.value = value; + + return; + } + + if( c < '0' || c > '9' ) { + break; + } + + lex.data++; + + } + + lex_immediateType = IT_INT; + lex_immediate.integer = integer; + +} + + + +/* +=============== +Lex_Whitespace +=============== +*/ +static void Lex_Eof( void ) { + lex.token[0] = 0; + lex.tokenLength = 0; + lex.tokenType = TT_EOF; +} + +/* +=============== +Lex_Check +=============== +*/ +qboolean Lex_Check( const char *check ) { + if( !strcmp( lex.token, check ) ) { + Lex(); + return qtrue; + } + return qfalse; +} + +/* +=============== +Lex_Expect +=============== +*/ +void Lex_Expect( const char *expect ) { + if( strcmp( lex.token, expect ) ) { + Lex_Error( "Expected '%s', found '%s'", expect, lex.token ); + } + Lex(); +} + +/* +=============== +Lex_ExpectToken +=============== +*/ +void Lex_ExpectToken( const char *expect ) { + if( strcmp( lex.token, expect ) ) { + Lex_Error( "Expected '%s', found '%s'", expect, lex.token ); + } +} + +/* +=============== +Lex_ExpectImmediate +=============== +*/ +void Lex_ExpectImmediate( lexImmType_t expect ) { + if( lex.tokenType != TT_IMMEDIATE ) { + Lex_Error( "Expected immediate, found '%s'", lex.token ); + } + if( ( lex_immediateType & expect ) == 0 ) { + Lex_Error( "Expected different immediate type" ); + } + Lex(); +} + +/* +=============== +Lex +=============== +*/ +void Lex( void ) { + int c; + + Lex_Whitespace(); + + c = *lex.data; + if( c >= 'A' && c <= 'z' ) { + Lex_Name(); + return; + } + if( c >= '0' && c <= '9' ) { + Lex_Number(); + return; + } + + switch( c ) { + case '\0': + Lex_Eof(); + break; + case '_': + Lex_Name(); + break; + case '\'': + Lex_Vector(); + break; + case '\"': + Lex_String(); + break; + default: + Lex_Punctuation(); + break; + } + +} + +void Lex_Begin( const char *data ) { + memset( &lex, 0, sizeof( lex ) ); + lex.data = data; + lex.currentLine = 1; + + memset( &lex_immediate, 0, sizeof( lex_immediate ) ); + lex_immediateType = IT_INT; + + Lex(); +} + + + + |