2012-04-09 10:42:06 +00:00
/*
* Copyright ( C ) 2012
* Dale Weiler
*
* Permission is hereby granted , free of charge , to any person obtaining a copy of
* this software and associated documentation files ( the " Software " ) , to deal in
* the Software without restriction , including without limitation the rights to
* use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies
* of the Software , and to permit persons to whom the Software is furnished to do
* so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
# include <limits.h>
2012-04-09 23:00:13 +00:00
# include <stdlib.h>
2012-04-10 00:10:52 +00:00
# include <string.h>
2012-04-11 16:13:31 +00:00
# include <ctype.h>
2012-04-09 10:42:06 +00:00
# include "gmqcc.h"
2012-04-09 11:45:20 +00:00
2012-04-15 11:59:22 +00:00
/* compile-time constant for type constants */
2012-04-14 08:17:06 +00:00
typedef struct {
char * name ;
int type ;
float value [ 3 ] ;
char * string ; /* string value if constant is string literal */
} constant ;
VECTOR_MAKE ( constant , compile_constants ) ;
2012-04-10 08:20:15 +00:00
/*
* Generates a parse tree out of the lexees generated by the lexer . This
* is where the tree is built . This is where valid check is performed .
*/
2012-04-15 11:59:22 +00:00
int parse_gen ( struct lex_file * file ) {
2012-04-09 10:42:06 +00:00
int token = 0 ;
2012-04-09 13:36:16 +00:00
while ( ( token = lex_token ( file ) ) ! = ERROR_LEX & & \
token ! = ERROR_COMPILER & & \
token ! = ERROR_INTERNAL & & \
token ! = ERROR_PARSE & & \
token ! = ERROR_PREPRO & & file - > length > = 0 ) {
2012-04-09 10:42:06 +00:00
switch ( token ) {
2012-04-10 00:10:52 +00:00
case TOKEN_TYPEDEF : {
2012-04-12 06:22:28 +00:00
char * f ; /* from */
char * t ; /* to */
2012-04-10 09:02:58 +00:00
2012-04-10 00:10:52 +00:00
token = lex_token ( file ) ;
2012-04-10 09:02:58 +00:00
token = lex_token ( file ) ; f = util_strdup ( file - > lastok ) ;
2012-04-10 00:10:52 +00:00
token = lex_token ( file ) ;
2012-04-10 09:02:58 +00:00
token = lex_token ( file ) ; t = util_strdup ( file - > lastok ) ;
2012-04-10 00:10:52 +00:00
typedef_add ( f , t ) ;
2012-04-10 09:02:58 +00:00
mem_d ( f ) ;
mem_d ( t ) ;
2012-04-10 05:03:52 +00:00
2012-04-12 02:13:34 +00:00
token = lex_token ( file ) ;
2012-04-12 06:22:28 +00:00
if ( token = = ' ' )
token = lex_token ( file ) ;
2012-04-12 02:13:34 +00:00
if ( token ! = ' ; ' )
2012-04-14 06:39:33 +00:00
error ( ERROR_PARSE , " %s:%d Expected a `;` at end of typedef statement \n " , file - > name , file - > line ) ;
2012-04-12 02:13:34 +00:00
token = lex_token ( file ) ;
2012-04-10 00:10:52 +00:00
break ;
}
2012-04-10 08:20:15 +00:00
2012-04-15 11:59:22 +00:00
case TOKEN_VOID : goto fall ;
case TOKEN_STRING : goto fall ;
case TOKEN_VECTOR : goto fall ;
case TOKEN_ENTITY : goto fall ;
case TOKEN_FLOAT : goto fall ;
2012-04-11 23:41:04 +00:00
{
2012-04-12 02:13:34 +00:00
fall : ;
2012-04-11 23:41:04 +00:00
char * name = NULL ;
2012-04-12 06:22:28 +00:00
int type = token ; /* story copy */
2012-04-11 23:41:04 +00:00
2012-04-12 06:22:28 +00:00
/* skip over space */
token = lex_token ( file ) ;
if ( token = = ' ' )
token = lex_token ( file ) ;
/* save name */
name = util_strdup ( file - > lastok ) ;
/* skip spaces */
token = lex_token ( file ) ;
if ( token = = ' ' )
token = lex_token ( file ) ;
2012-04-11 23:41:04 +00:00
2012-04-12 06:22:28 +00:00
if ( token = = ' ; ' ) {
2012-04-14 06:39:33 +00:00
/*
* Definitions go to the defs table , they don ' t have
* any sort of data with them yet .
*/
2012-04-12 06:22:28 +00:00
} else if ( token = = ' = ' ) {
token = lex_token ( file ) ;
if ( token = = ' ' )
2012-04-11 23:41:04 +00:00
token = lex_token ( file ) ;
2012-04-12 06:22:28 +00:00
/* strings are in file->lastok */
switch ( type ) {
2012-04-14 06:39:33 +00:00
case TOKEN_VOID :
return error ( ERROR_PARSE , " %s:%d Cannot assign value to type void \n " , file - > name , file - > line ) ;
2012-04-14 08:17:06 +00:00
/* TODO: Validate (end quote), strip quotes for constant add, name constant */
2012-04-12 06:22:28 +00:00
case TOKEN_STRING :
if ( * file - > lastok ! = ' " ' )
2012-04-14 06:39:33 +00:00
error ( ERROR_PARSE , " %s:%d Expected a ' \" ' (quote) for string constant \n " , file - > name , file - > line ) ;
2012-04-14 08:17:06 +00:00
/* add the compile-time constant */
compile_constants_add ( ( constant ) {
. name = util_strdup ( name ) ,
. type = TYPE_STRING ,
. value = { 0 , 0 , 0 } ,
. string = util_strdup ( file - > lastok )
} ) ;
2012-04-12 06:22:28 +00:00
break ;
2012-04-14 08:17:06 +00:00
/* TODO: name constant, old qc vec literals, whitespace fixes, name constant */
2012-04-12 06:22:28 +00:00
case TOKEN_VECTOR : {
float compile_calc_x = 0 ;
float compile_calc_y = 0 ;
float compile_calc_z = 0 ;
2012-04-14 06:39:33 +00:00
int compile_calc_d = 0 ; /* dot? */
int compile_calc_s = 0 ; /* sign (-, +) */
2012-04-12 06:22:28 +00:00
char compile_data [ 1024 ] ;
char * compile_eval = compile_data ;
if ( token ! = ' { ' )
error ( ERROR_PARSE , " %s:%d Expected initializer list `{`,`}` for vector constant \n " , file - > name , file - > line ) ;
/*
2012-04-14 06:39:33 +00:00
* This parses a single vector element : x , y & z . This will handle all the
* complicated mechanics of a vector , and can be extended as well . This
2012-04-14 07:58:28 +00:00
* is a rather large macro , and is # undef ' d after it ' s use below .
2012-04-12 06:22:28 +00:00
*/
2012-04-14 06:48:11 +00:00
# define PARSE_VEC_ELEMENT(NAME, BIT) \
2012-04-14 06:51:52 +00:00
token = lex_token ( file ) ; \
2012-04-14 07:58:28 +00:00
if ( token = = ' ' ) \
2012-04-14 06:51:52 +00:00
token = lex_token ( file ) ; \
2012-04-14 07:58:28 +00:00
if ( token = = ' . ' ) \
2012-04-14 06:51:52 +00:00
compile_calc_d = 1 ; \
2012-04-14 07:58:28 +00:00
if ( ! isdigit ( token ) & & ! compile_calc_d & & token ! = ' + ' & & token ! = ' - ' ) \
2012-04-14 06:51:52 +00:00
error ( ERROR_PARSE , " %s:%d Invalid constant initializer element %c for vector, must be numeric \n " , file - > name , file - > line , NAME ) ; \
2012-04-14 07:58:28 +00:00
if ( token = = ' + ' ) \
2012-04-14 06:51:52 +00:00
compile_calc_s = ' + ' ; \
2012-04-14 07:58:28 +00:00
if ( token = = ' - ' & & ! compile_calc_s ) \
2012-04-14 06:51:52 +00:00
compile_calc_s = ' - ' ; \
while ( isdigit ( token ) | | token = = ' . ' | | token = = ' + ' | | token = = ' - ' ) { \
* compile_eval + + = token ; \
token = lex_token ( file ) ; \
if ( token = = ' . ' & & compile_calc_d ) { \
error ( ERROR_PARSE , " %s:%d Invalid constant initializer element %c for vector, must be numeric. \n " , file - > name , file - > line , NAME ) ; \
token = lex_token ( file ) ; \
} \
if ( ( token = = ' - ' | | token = = ' + ' ) & & compile_calc_s ) { \
error ( ERROR_PARSE , " %s:%d Invalid constant initializer sign for vector element %c \n " , file - > name , file - > line , NAME ) ; \
token = lex_token ( file ) ; \
2012-04-14 07:58:28 +00:00
} \
else if ( token = = ' . ' & & ! compile_calc_d ) \
2012-04-14 06:51:52 +00:00
compile_calc_d = 1 ; \
2012-04-14 07:58:28 +00:00
else if ( token = = ' - ' & & ! compile_calc_s ) \
2012-04-14 06:51:52 +00:00
compile_calc_s = ' - ' ; \
2012-04-14 07:58:28 +00:00
else if ( token = = ' + ' & & ! compile_calc_s ) \
2012-04-14 06:51:52 +00:00
compile_calc_s = ' + ' ; \
} \
2012-04-14 07:58:28 +00:00
if ( token = = ' ' ) \
2012-04-14 06:51:52 +00:00
token = lex_token ( file ) ; \
if ( NAME ! = ' z ' ) { \
2012-04-14 07:58:28 +00:00
if ( token ! = ' , ' & & token ! = ' ' ) \
2012-04-14 07:08:15 +00:00
error ( ERROR_PARSE , " %s:%d invalid constant initializer element %c for vector (missing spaces, or comma delimited list?) \n " , file - > name , file - > line , NAME ) ; \
2012-04-14 06:51:52 +00:00
} else if ( token ! = ' } ' ) { \
error ( ERROR_PARSE , " %s:%d Expected `}` on end of constant initialization for vector \n " , file - > name , file - > line ) ; \
} \
compile_calc_ # # BIT = atof ( compile_data ) ; \
compile_calc_d = 0 ; \
compile_calc_s = 0 ; \
compile_eval = & compile_data [ 0 ] ; \
memset ( compile_data , 0 , sizeof ( compile_data ) )
2012-04-12 06:22:28 +00:00
/*
2012-04-14 06:39:33 +00:00
* Parse all elements using the macro above .
* We must undef the macro afterwards .
2012-04-12 06:22:28 +00:00
*/
2012-04-14 06:39:33 +00:00
PARSE_VEC_ELEMENT ( ' x ' , x ) ;
PARSE_VEC_ELEMENT ( ' y ' , y ) ;
PARSE_VEC_ELEMENT ( ' z ' , z ) ;
# undef PARSE_VEC_ELEMENT
2012-04-12 06:22:28 +00:00
2012-04-14 07:58:28 +00:00
/* Check for the semi-colon... */
2012-04-11 23:41:04 +00:00
token = lex_token ( file ) ;
2012-04-12 06:22:28 +00:00
if ( token = = ' ' )
token = lex_token ( file ) ;
if ( token ! = ' ; ' )
error ( ERROR_PARSE , " %s:%d Expected `;` on end of constant initialization for vector \n " , file - > name , file - > line ) ;
2012-04-14 06:39:33 +00:00
2012-04-14 08:17:06 +00:00
/* add the compile-time constant */
compile_constants_add ( ( constant ) {
. name = util_strdup ( name ) ,
. type = TYPE_VECTOR ,
. value = {
[ 0 ] = compile_calc_x ,
[ 1 ] = compile_calc_y ,
[ 2 ] = compile_calc_z
} ,
. string = NULL
} ) ;
2012-04-12 06:22:28 +00:00
break ;
2012-04-11 23:41:04 +00:00
}
2012-04-12 06:22:28 +00:00
case TOKEN_ENTITY :
2012-04-14 08:17:06 +00:00
case TOKEN_FLOAT : /*TODO: validate, constant generation, name constant */
2012-04-12 06:22:28 +00:00
if ( ! isdigit ( token ) )
error ( ERROR_PARSE , " %s:%d Expected numeric constant for float constant \n " ) ;
2012-04-14 08:17:06 +00:00
compile_constants_add ( ( constant ) {
. name = util_strdup ( name ) ,
. type = TOKEN_FLOAT ,
. value = { 0 , 0 , 0 } ,
. string = NULL
} ) ;
2012-04-12 06:22:28 +00:00
break ;
}
} else if ( token = = ' ( ' ) {
printf ( " FUNCTION ?? \n " ) ;
2012-04-11 23:41:04 +00:00
}
mem_d ( name ) ;
}
2012-04-09 14:14:26 +00:00
2012-04-09 23:00:13 +00:00
/*
* From here down is all language punctuation : There is no
* need to actual create tokens from these because they ' re already
* tokenized as these individual tokens ( which are in a special area
* of the ascii table which doesn ' t conflict with our other tokens
2012-04-10 00:39:54 +00:00
* which are higer than the ascii table . )
2012-04-09 23:00:13 +00:00
*/
2012-04-10 01:32:24 +00:00
case ' # ' :
2012-04-11 16:13:31 +00:00
token = lex_token ( file ) ; /* skip '#' */
2012-04-14 06:39:33 +00:00
if ( token = = ' ' )
token = lex_token ( file ) ;
2012-04-10 01:32:24 +00:00
/*
2012-04-11 16:13:31 +00:00
* If we make it here we found a directive , the supported
* directives so far are # include .
2012-04-10 01:32:24 +00:00
*/
2012-04-11 16:13:31 +00:00
if ( strncmp ( file - > lastok , " include " , sizeof ( " include " ) ) = = 0 ) {
/*
2012-04-11 19:53:40 +00:00
* We only suport include " " , not < > like in C ( why ? )
* because the latter is silly .
2012-04-11 16:13:31 +00:00
*/
while ( * file - > lastok ! = ' " ' & & token ! = ' \n ' )
token = lex_token ( file ) ;
2012-04-11 19:53:40 +00:00
if ( token = = ' \n ' )
2012-04-14 06:39:33 +00:00
return error ( ERROR_PARSE , " %d: Invalid use of include preprocessor directive: wanted #include \" file.h \" \n " , file - > line - 1 ) ;
2012-04-14 07:53:20 +00:00
char * copy = util_strdup ( file - > lastok ) ;
struct lex_file * next = lex_include ( file , copy ) ;
if ( ! next ) {
error ( ERROR_INTERNAL , " Include subsystem failure \n " ) ;
exit ( - 1 ) ;
}
2012-04-15 11:59:22 +00:00
parse_gen ( next ) ;
mem_d ( copy ) ;
lex_close ( next ) ;
2012-04-11 16:13:31 +00:00
}
2012-04-10 01:32:24 +00:00
/* skip all tokens to end of directive */
while ( token ! = ' \n ' )
token = lex_token ( file ) ;
break ;
2012-04-10 02:44:06 +00:00
case LEX_IDENT :
token = lex_token ( file ) ;
break ;
2012-04-09 10:42:06 +00:00
}
}
lex_reset ( file ) ;
return 1 ;
}