X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=gmqcc.h;h=df123c6c42713c733446ee21c1eb8c1773cf4409;hb=52b4c9f0c10267fbba0c81336de56265ed0c6f4d;hp=c42197011c2617449aba7d2429e5b6184e8f99d0;hpb=d1373af7fc9b4657b1fb663bf6ea03c73e9ab8c7;p=xonotic%2Fgmqcc.git diff --git a/gmqcc.h b/gmqcc.h index c421970..df123c6 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2012 - * Dale Weiler, Wolfgang Bumiller + * Dale Weiler + * Wolfgang Bumiller * * 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 @@ -41,7 +42,7 @@ #endif #define GMQCC_VERSION_MAJOR 0 -#define GMQCC_VERSION_MINOR 1 +#define GMQCC_VERSION_MINOR 2 #define GMQCC_VERSION_PATCH 0 #define GMQCC_VERSION_BUILD(J,N,P) (((J)<<16)|((N)<<8)|(P)) #define GMQCC_VERSION \ @@ -110,6 +111,13 @@ # else # define GMQCC_INLINE inline # endif +/* + * Visual studio has __forcinline we can use. So lets use that + * I suspect it also has just __inline of some sort, but our use + * of inline is correct (not guessed), WE WANT IT TO BE INLINE + */ +#elseif defined(_MSC_VER) +# define GMQCC_INLINE __forceinline #else # define GMQCC_INLINE #endif /* !__STDC_VERSION__ */ @@ -153,14 +161,14 @@ #if defined(__GNUC__) || defined (__CLANG__) - typedef int int64_t __attribute__((__mode__(__DI__))); - typedef unsigned int uint64_t __attribute__((__mode__(__DI__))); + typedef int int64_t __attribute__((__mode__(__DI__))); + typedef unsigned int uint64_t __attribute__((__mode__(__DI__))); #elif defined(_MSC_VER) typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #else /* - * Incoorectly size the types so static assertions below will + * Incorrectly size the types so static assertions below will * fail. There is no valid way to get a 64bit type at this point * without making assumptions of too many things. */ @@ -196,6 +204,7 @@ void util_memory_d (void *, unsigned int, const char *); void *util_memory_r (void *, size_t, unsigned int, const char *); void util_meminfo (); +bool util_filexists (const char *); bool util_strupper (const char *); bool util_strdigit (const char *); bool util_strncmpexact (const char *, const char *, size_t); @@ -233,27 +242,78 @@ uint32_t util_crc32(uint32_t crc, const char *data, size_t len); #define INT2FLT(Y) *((float *)&(Y)) /* New flexible vector implementation from Dale */ -#define _vec_raw(A) (((size_t*)(A)) - 2) +#define _vec_raw(A) (((size_t*)(void*)(A)) - 2) #define _vec_beg(A) (_vec_raw(A)[0]) #define _vec_end(A) (_vec_raw(A)[1]) #define _vec_needsgrow(A,N) ((!(A)) || (_vec_end(A) + (N) >= _vec_beg(A))) -#define _vec_mightgrow(A,N) (_vec_needsgrow((A), (N)) ? _vec_forcegrow((A),(N)) : 0) -#define _vec_forcegrow(A,N) _util_vec_grow((void**)&(A), (N), sizeof(*(A))) -#define _vec_remove(A,S,I,N) (memmove((char*)(A)+(I)*(S),(char*)(A)+((I)+(N))*(S),(S)*(vec_size(A)-(I)-(N))), _vec_end(A)-=(N)) +#define _vec_mightgrow(A,N) (_vec_needsgrow((A), (N)) ? (void)_vec_forcegrow((A),(N)) : (void)0) +#define _vec_forcegrow(A,N) _util_vec_grow(((void**)&(A)), (N), sizeof(*(A))) +#define _vec_remove(A,S,I,N) (memmove((char*)(A)+(I)*(S),(char*)(A)+((I)+(N))*(S),(S)*(_vec_end(A)-(I)-(N))), _vec_end(A)-=(N)) void _util_vec_grow(void **a, size_t i, size_t s); /* exposed interface */ -#define vec_free(A) ((A) ? (mem_d(_vec_raw(A)), (A) = NULL) : 0) +#define vec_free(A) ((A) ? (mem_d((void*)_vec_raw(A)), (A) = NULL) : 0) #define vec_push(A,V) (_vec_mightgrow((A),1), (A)[_vec_end(A)++] = (V)) #define vec_size(A) ((A) ? _vec_end(A) : 0) #define vec_add(A,N) (_vec_mightgrow((A),(N)), _vec_end(A)+=(N), &(A)[_vec_end(A)-(N)]) #define vec_last(A) ((A)[_vec_end(A)-1]) #define vec_append(A,N,S) memcpy(vec_add((A), (N)), (S), N * sizeof(*(S))) #define vec_remove(A,I,N) _vec_remove((A), sizeof(*(A)), (I), (N)) -#define vec_pop(A) vec_remove((A), _vec_end(A)-1, 1) +#define vec_pop(A) (_vec_end(A)-=1) /* these are supposed to NOT reallocate */ #define vec_shrinkto(A,N) (_vec_end(A) = (N)) #define vec_shrinkby(A,N) (_vec_end(A) -= (N)) +#define vec_upload(X,Y,S) \ + do { \ + size_t E = 0; \ + while (E < S) { \ + vec_push(X, Y[E]); \ + E ++; \ + } \ + } while(0) + +typedef struct hash_table_t { + size_t size; + struct hash_node_t **table; +} hash_table_t, *ht; + +/* + * hashtable implementation: + * + * Note: + * This was designed for pointers: you manage the life of the object yourself + * if you do use this for non-pointers please be warned that the object may not + * be valid if the duration of it exceeds (i.e on stack). So you need to allocate + * yourself, or put those in global scope to ensure duration is for the whole + * runtime. + * + * util_htnew(size) -- to make a new hashtable + * util_htset(table, key, value, sizeof(value)) -- to set something in the table + * util_htget(table, key) -- to get something from the table + * util_htdel(table) -- to delete the table + * + * example of use: + * + * ht foo = util_htnew(1024); + * int data = 100; + * char *test = "hello world\n"; + * util_htset(foo, "foo", (void*)&data); + * util_gtset(foo, "bar", (void*)test); + * + * printf("foo: %d, bar %s", + * *((int *)util_htget(foo, "foo")), + * ((char*)util_htget(foo, "bar")) + * ); + * + * util_htdel(foo); + */ +hash_table_t *util_htnew (size_t size); +void util_htset (hash_table_t *ht, const char *key, void *value); +void *util_htget (hash_table_t *ht, const char *key); +void util_htdel (hash_table_t *ht); +size_t util_hthash(hash_table_t *ht, const char *key); +void *util_htgeth(hash_table_t *ht, const char *key, size_t hash); +void util_htseth(hash_table_t *ht, const char *key, size_t hash, void *value); /*===================================================================*/ /*=========================== code.c ================================*/ /*===================================================================*/ @@ -277,20 +337,28 @@ enum { TYPE_COUNT }; -extern const char *type_name[TYPE_COUNT]; +/* const/var qualifiers */ +#define CV_NONE 0 +#define CV_CONST 1 +#define CV_VAR -1 +/* magic number to help parsing */ +#define CV_WRONG 0x8000 + +extern const char *type_name [TYPE_COUNT]; +extern size_t type_sizeof [TYPE_COUNT]; +extern uint16_t type_store_instr [TYPE_COUNT]; +extern uint16_t field_store_instr[TYPE_COUNT]; -extern size_t type_sizeof[TYPE_COUNT]; -extern uint16_t type_store_instr[TYPE_COUNT]; -extern uint16_t field_store_instr[TYPE_COUNT]; -/* could use type_store_instr + INSTR_STOREP_F - INSTR_STORE_F +/* + * could use type_store_instr + INSTR_STOREP_F - INSTR_STORE_F * but this breaks when TYPE_INTEGER is added, since with the enhanced * instruction set, the old ones are left untouched, thus the _I instructions * are at a seperate place. */ extern uint16_t type_storep_instr[TYPE_COUNT]; -/* other useful lists */ -extern uint16_t type_eq_instr[TYPE_COUNT]; -extern uint16_t type_ne_instr[TYPE_COUNT]; +extern uint16_t type_eq_instr [TYPE_COUNT]; +extern uint16_t type_ne_instr [TYPE_COUNT]; +extern uint16_t type_not_instr [TYPE_COUNT]; typedef struct { uint32_t offset; /* Offset in file of where data begins */ @@ -299,15 +367,15 @@ typedef struct { typedef struct { uint32_t version; /* Program version (6) */ - uint16_t crc16; /* What is this? */ - uint16_t skip; /* see propsal.txt */ + uint16_t crc16; + uint16_t skip; prog_section statements; /* prog_section_statement */ prog_section defs; /* prog_section_def */ prog_section fields; /* prog_section_field */ prog_section functions; /* prog_section_function */ - prog_section strings; /* What is this? */ - prog_section globals; /* What is this? */ + prog_section strings; + prog_section globals; uint32_t entfield; /* Number of entity fields */ } prog_header; @@ -357,7 +425,8 @@ typedef struct { } prog_section_statement; typedef struct { - /* The types: + /* + * The types: * 0 = ev_void * 1 = ev_string * 2 = ev_float @@ -372,6 +441,7 @@ typedef struct { uint16_t offset; uint32_t name; } prog_section_both; + typedef prog_section_both prog_section_def; typedef prog_section_both prog_section_field; @@ -386,7 +456,7 @@ typedef struct { uint32_t profile; /* Always zero (engine uses this) */ uint32_t name; /* name of function in string table */ uint32_t file; /* file of the source file */ - uint32_t nargs; /* number of arguments */ + int32_t nargs; /* number of arguments */ uint8_t argsize[8]; /* size of arguments (keep 8 always?) */ } prog_section_function; @@ -480,6 +550,7 @@ enum { }; extern prog_section_statement *code_statements; +extern int *code_linenums; extern prog_section_def *code_defs; extern prog_section_field *code_fields; extern prog_section_function *code_functions; @@ -494,12 +565,25 @@ typedef int32_t qcint; * code_write -- writes out the compiled file * code_init -- prepares the code file */ -bool code_write (const char *filename); +bool code_write (const char *filename, const char *lno); void code_init (); uint32_t code_genstring (const char *string); uint32_t code_cachedstring(const char *string); qcint code_alloc_field (size_t qcsize); +/* this function is used to keep statements and linenumbers together */ +void code_push_statement(prog_section_statement *stmt, int linenum); +void code_pop_statement(); + +/* + * A shallow copy of a lex_file to remember where which ast node + * came from. + */ +typedef struct { + const char *file; + size_t line; +} lex_ctx; + /*===================================================================*/ /*============================ con.c ================================*/ /*===================================================================*/ @@ -521,21 +605,29 @@ enum { LVL_ERROR }; - void con_vprintmsg (int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap); void con_printmsg (int level, const char *name, size_t line, const char *msgtype, const char *msg, ...); void con_cvprintmsg(void *ctx, int lvl, const char *msgtype, const char *msg, va_list ap); void con_cprintmsg (void *ctx, int lvl, const char *msgtype, const char *msg, ...); -void con_close(); -void con_color(int state); -void con_init (); -void con_reset(); -int con_change(const char *out, const char *err); -int con_verr (const char *fmt, va_list va); -int con_vout (const char *fmt, va_list va); -int con_err (const char *fmt, ...); -int con_out (const char *fmt, ...); +void con_close (); +void con_init (); +void con_reset (); +void con_color (int); +int con_change(const char *, const char *); +int con_verr (const char *, va_list); +int con_vout (const char *, va_list); +int con_err (const char *, ...); +int con_out (const char *, ...); + +/* error/warning interface */ +extern size_t compile_errors; +extern size_t compile_warnings; + +void /********/ compile_error (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, ...); +void /********/ vcompile_error (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, va_list ap); +bool GMQCC_WARN compile_warning (lex_ctx ctx, int warntype, const char *fmt, ...); +bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_list ap); /*===================================================================*/ /*========================= assembler.c =============================*/ @@ -635,20 +727,12 @@ vector vec3_sub (vector, vector); qcfloat vec3_mulvv(vector, vector); vector vec3_mulvf(vector, float); -/* - * A shallow copy of a lex_file to remember where which ast node - * came from. - */ -typedef struct { - const char *file; - size_t line; -} lex_ctx; - /*===================================================================*/ /*============================= exec.c ==============================*/ /*===================================================================*/ -/* darkplaces has (or will have) a 64 bit prog loader +/* + * Darkplaces has (or will have) a 64 bit prog loader * where the 32 bit qc program is autoconverted on load. * Since we may want to support that as well, let's redefine * float and int here. @@ -751,14 +835,20 @@ bool parser_compile_file (const char *filename); bool parser_compile_string(const char *name, const char *str); bool parser_finish (const char *output); void parser_cleanup (); +/* There's really no need to strlen() preprocessed files */ +bool parser_compile_string_len(const char *name, const char *str, size_t len); /*===================================================================*/ /*====================== ftepp.c commandline ========================*/ /*===================================================================*/ -bool ftepp_init (FILE *out); +bool ftepp_init (); bool ftepp_preprocess_file (const char *filename); bool ftepp_preprocess_string(const char *name, const char *str); void ftepp_finish (); +const char *ftepp_get (); +void ftepp_flush (); +void ftepp_add_define (const char *source, const char *name); +void ftepp_add_macro (const char *name, const char *value); /*===================================================================*/ /*======================= main.c commandline ========================*/ @@ -778,14 +868,23 @@ typedef uint32_t longbit; #define LONGBIT(bit) (bit) #endif -/* Used to store the list of flags with names */ +/*===================================================================*/ +/*============================= opts.c ==============================*/ +/*===================================================================*/ typedef struct { const char *name; - longbit bit; + longbit bit; } opts_flag_def; -/*===================================================================*/ -/* list of -f flags, like -fdarkplaces-string-table-bug */ +bool opts_setflag (const char *, bool); +bool opts_setwarn (const char *, bool); +bool opts_setoptim(const char *, bool); + +void opts_init (const char *, int, size_t); +void opts_set (uint32_t *, size_t, bool); +void opts_setoptimlevel(unsigned int); +void opts_ini_init (const char *); + enum { # define GMQCC_TYPE_FLAGS # define GMQCC_DEFINE_FLAG(X) X, @@ -812,29 +911,59 @@ static const opts_flag_def opts_warn_list[] = { { NULL, LONGBIT(0) } }; -/* other options: */ enum { +# define GMQCC_TYPE_OPTIMIZATIONS +# define GMQCC_DEFINE_FLAG(NAME, MIN_O) OPTIM_##NAME, +# include "opts.def" + COUNT_OPTIMIZATIONS +}; +static const opts_flag_def opts_opt_list[] = { +# define GMQCC_TYPE_OPTIMIZATIONS +# define GMQCC_DEFINE_FLAG(NAME, MIN_O) { #NAME, LONGBIT(OPTIM_##NAME) }, +# include "opts.def" + { NULL, LONGBIT(0) } +}; +static const unsigned int opts_opt_oflag[] = { +# define GMQCC_TYPE_OPTIMIZATIONS +# define GMQCC_DEFINE_FLAG(NAME, MIN_O) MIN_O, +# include "opts.def" + 0 +}; +extern unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS]; + +/* other options: */ +typedef enum { COMPILER_QCC, /* circa QuakeC */ COMPILER_FTEQCC, /* fteqcc QuakeC */ COMPILER_QCCX, /* qccx QuakeC */ COMPILER_GMQCC /* this QuakeC */ -}; -extern uint32_t opts_O; /* -Ox */ -extern const char *opts_output; /* -o file */ -extern int opts_standard; -extern bool opts_debug; -extern bool opts_memchk; -extern bool opts_dump; -extern bool opts_werror; -extern bool opts_forcecrc; -extern uint16_t opts_forced_crc; -extern bool opts_pp_only; -extern size_t opts_max_array_size; +} opts_std_t; + +typedef struct { + uint32_t O; /* -Ox */ + const char *output; /* -o file */ + bool g; /* -g */ + opts_std_t standard; /* -std= */ + bool debug; /* -debug */ + bool memchk; /* -memchk */ + bool dumpfin; /* -dumpfin */ + bool dump; /* -dump */ + bool werror; /* -Werror */ + bool forcecrc; /* --force-crc= */ + uint16_t forced_crc; /* --force-crc= */ + bool pp_only; /* -E */ + size_t max_array_size; /* --max-array= */ + + uint32_t flags [1 + (COUNT_FLAGS / 32)]; + uint32_t warn [1 + (COUNT_WARNINGS / 32)]; + uint32_t optimization[1 + (COUNT_OPTIMIZATIONS / 32)]; +} opts_cmd_t; + +extern opts_cmd_t opts; /*===================================================================*/ -#define OPTS_FLAG(i) (!! (opts_flags[(i)/32] & (1<< ((i)%32)))) -extern uint32_t opts_flags[1 + (COUNT_FLAGS / 32)]; -#define OPTS_WARN(i) (!! (opts_warn[(i)/32] & (1<< ((i)%32)))) -extern uint32_t opts_warn[1 + (COUNT_WARNINGS / 32)]; +#define OPTS_FLAG(i) (!! (opts.flags [(i)/32] & (1<< ((i)%32)))) +#define OPTS_WARN(i) (!! (opts.warn [(i)/32] & (1<< ((i)%32)))) +#define OPTS_OPTIMIZATION(i) (!! (opts.optimization[(i)/32] & (1<< ((i)%32)))) #endif