X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=gmqcc.h;h=10b74f5ab2741e92ff9421fc7a3d8bc2ac888244;hp=34c0ed8ff60833d5a667f83b68bfd04a3d29f28d;hb=f971f89e1e239a74fd34f9f5369993b25d5432ed;hpb=e8133893a0bd4e1cc469864b3d6f621ed5f3186f diff --git a/gmqcc.h b/gmqcc.h index 34c0ed8..10b74f5 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -1,30 +1,14 @@ -/* - * Copyright (C) 2012, 2013, 2014 - * 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 - * 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. - */ #ifndef GMQCC_HDR #define GMQCC_HDR +#include +#include +#include +#include +using std::move; #include #include +#include +#include #include #define GMQCC_VERSION_MAJOR 0 @@ -178,34 +162,15 @@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) \ #define GMQCC_ARRAY_COUNT(X) (sizeof(X) / sizeof((X)[0])) /* stat.c */ -void stat_info (void); -char *stat_mem_strdup (const char *, size_t, const char *, bool); -void *stat_mem_reallocate(void *, size_t, size_t, const char *, const char *); -void stat_mem_deallocate(void *); -void *stat_mem_allocate (size_t, size_t, const char *, const char *); +char *stat_mem_strdup(const char *, bool); -#define mem_a(SIZE) stat_mem_allocate ((SIZE), __LINE__, __FILE__, #SIZE) -#define mem_d(PTRN) stat_mem_deallocate((void*)(PTRN)) -#define mem_r(PTRN, SIZE) stat_mem_reallocate((void*)(PTRN), (SIZE), __LINE__, __FILE__, #SIZE) -#define mem_af(SIZE, FILE, LINE) stat_mem_allocate ((SIZE), (LINE), (FILE), #SIZE) +#define mem_a(SIZE) malloc(SIZE) +#define mem_d(PTRN) free((void*)PTRN) +#define mem_r(PTRN, SIZE) realloc((void*)PTRN, SIZE) -/* TODO: rename to mem variations */ -#define util_strdup(SRC) stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, false) -#define util_strdupe(SRC) stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, true) +#define util_strdup(SRC) stat_mem_strdup((char*)(SRC), false) +#define util_strdupe(SRC) stat_mem_strdup((char*)(SRC), true) -/* util.c */ - -/* - * Microsoft implements against the spec versions of ctype.h. Which - * means what ever the current set locale is will render the actual - * results of say isalpha('A') wrong for what ever retarded locale - * is used. Simalerly these are also implemented inefficently on - * some toolchains and end up becoming actual library calls. Perhaps - * this is why tools like yacc provide their own? Regardless implementing - * these as functions is equally as silly, the call overhead is not - * justified when this could happen on every character from an input - * stream. We provide our own as macros for absolute inlinability. - */ #define util_isalpha(a) ((((unsigned)(a)|32)-'a') < 26) #define util_isdigit(a) (((unsigned)(a)-'0') < 10) #define util_islower(a) (((unsigned)(a)-'a') < 26) @@ -237,9 +202,7 @@ const char *util_strerror(int err); const struct tm *util_localtime(const time_t *timer); const char *util_ctime (const time_t *timer); -typedef struct fs_file_s fs_file_t; - -bool util_isatty(fs_file_t *); +bool util_isatty(FILE *); size_t hash(const char *key); /* @@ -249,24 +212,26 @@ size_t hash(const char *key); * us to use the array [] to access individual elements from the vector * opposed to using set/get methods. */ -typedef struct { +struct vector_t { size_t allocated; size_t used; /* can be extended now! whoot */ -} vector_t; +}; /* hidden interface */ void _util_vec_grow(void **a, size_t i, size_t s); -#define GMQCC_VEC_WILLGROW(X,Y) ( \ +void _util_vec_delete(void *vec); + +#define GMQCC_VEC_WILLGROW(X, Y) ( \ ((!(X) || vec_meta(X)->used + Y >= vec_meta(X)->allocated)) ? \ (void)_util_vec_grow(((void**)&(X)), (Y), sizeof(*(X))) : \ (void)0 \ ) /* exposed interface */ -#define vec_meta(A) (((vector_t*)((void*)A)) - 1) -#define vec_free(A) ((void)((A) ? (mem_d((void*)vec_meta(A)), (A) = NULL) : 0)) +#define vec_meta(A) ((vector_t*)(((char *)(A)) - sizeof(vector_t))) +#define vec_free(A) ((void)((A) ? (_util_vec_delete((void *)(A)), (A) = nullptr) : 0)) #define vec_push(A,V) (GMQCC_VEC_WILLGROW((A),1), (A)[vec_meta(A)->used++] = (V)) #define vec_size(A) ((A) ? vec_meta(A)->used : 0) #define vec_add(A,N) (GMQCC_VEC_WILLGROW((A),(N)), vec_meta(A)->used += (N), &(A)[vec_meta(A)->used-(N)]) @@ -282,106 +247,23 @@ typedef struct hash_table_s { 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_htrem (hash_table_t *ht, void (*callback)(void *data)); -void util_htset (hash_table_t *ht, const char *key, void *value); -void util_htdel (hash_table_t *ht); -size_t util_hthash(hash_table_t *ht, const char *key); -void util_htseth(hash_table_t *ht, const char *key, size_t hash, void *value); -void util_htrmh (hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)); -void util_htrm (hash_table_t *ht, const char *key, void (*cb)(void*)); - -void *util_htget (hash_table_t *ht, const char *key); -void *util_htgeth(hash_table_t *ht, const char *key, size_t hash); - -int util_snprintf(char *str, size_t, const char *fmt, ...); - - -/* fs.c */ -#define FS_FILE_SEEK_SET 0 -#define FS_FILE_SEEK_CUR 1 -#define FS_FILE_SEEK_END 2 -#define FS_FILE_EOF -1 - -typedef struct fs_dir_s fs_dir_t; -/*typedef struct fs_file_s fs_file_t;*/ -typedef struct dirent fs_dirent_t; - -void fs_file_close (fs_file_t *); -int fs_file_error (fs_file_t *); -int fs_file_getc (fs_file_t *); -int fs_file_printf (fs_file_t *, const char *, ...); -int fs_file_puts (fs_file_t *, const char *); -int fs_file_seek (fs_file_t *, long int, int); -long fs_file_tell (fs_file_t *); -int fs_file_flush (fs_file_t *); - -size_t fs_file_read (void *, size_t, size_t, fs_file_t *); -size_t fs_file_write (const void *, size_t, size_t, fs_file_t *); - -fs_file_t *fs_file_open (const char *, const char *); -int fs_file_getline(char **, size_t *, fs_file_t *); - -int fs_dir_make (const char *); -fs_dir_t *fs_dir_open (const char *); -int fs_dir_close (fs_dir_t *); -fs_dirent_t *fs_dir_read (fs_dir_t *); - - -/* correct.c */ -typedef struct correct_trie_s { - void *value; - struct correct_trie_s *entries; -} correct_trie_t; - -correct_trie_t* correct_trie_new(void); - -typedef struct { - char ***edits; - size_t **lens; -} correction_t; - -void correct_del (correct_trie_t*, size_t **); -void correct_add (correct_trie_t*, size_t ***, const char *); -char *correct_str (correction_t *, correct_trie_t*, const char *); -void correct_init(correction_t *); -void correct_free(correction_t *); - +void util_htrem(hash_table_t *ht, void (*callback)(void *data)); +void util_htset(hash_table_t *ht, const char *key, void *value); +void util_htdel(hash_table_t *ht); +size_t util_hthash(hash_table_t *ht, const char *key); +void util_htseth(hash_table_t *ht, const char *key, size_t hash, void *value); +void util_htrmh(hash_table_t *ht, const char *key, size_t bin, void (*cb)(void*)); +void util_htrm(hash_table_t *ht, const char *key, void (*cb)(void*)); +void *util_htget(hash_table_t *ht, const char *key); +void *util_htgeth(hash_table_t *ht, const char *key, size_t hash); +int util_snprintf(char *str, size_t, const char *fmt, ...); +int util_getline(char **, size_t *, FILE *); /* code.c */ /* Note: if you change the order, fix type_sizeof in ir.c */ -enum { +enum qc_type { TYPE_VOID , TYPE_STRING , TYPE_FLOAT , @@ -423,12 +305,12 @@ extern const uint16_t type_eq_instr [TYPE_COUNT]; extern const uint16_t type_ne_instr [TYPE_COUNT]; extern const uint16_t type_not_instr [TYPE_COUNT]; -typedef struct { +struct prog_section_t { uint32_t offset; /* Offset in file of where data begins */ uint32_t length; /* Length of section (how many of) */ -} prog_section_t; +}; -typedef struct { +struct prog_header_t { uint32_t version; /* Program version (6) */ uint16_t crc16; uint16_t skip; @@ -440,7 +322,7 @@ typedef struct { prog_section_t strings; prog_section_t globals; uint32_t entfield; /* Number of entity fields */ -} prog_header_t; +}; /* * Each paramater incerements by 3 since vector types hold @@ -457,37 +339,19 @@ typedef struct { #define OFS_PARM6 (OFS_PARM5 +3) #define OFS_PARM7 (OFS_PARM6 +3) -typedef struct { - uint16_t opcode; - - /* operand 1 */ - union { - int16_t s1; /* signed */ - uint16_t u1; /* unsigned */ - } o1; - /* operand 2 */ - union { - int16_t s1; /* signed */ - uint16_t u1; /* unsigned */ - } o2; - /* operand 3 */ - union { - int16_t s1; /* signed */ - uint16_t u1; /* unsigned */ - } o3; +union operand_t { + int16_t s1; + uint16_t u1; +}; - /* - * This is the same as the structure in darkplaces - * { - * unsigned short op; - * short a,b,c; - * } - * But this one is more sane to work with, and the - * type sizes are guranteed. - */ -} prog_section_statement_t; +struct prog_section_statement_t { + uint16_t opcode; + operand_t o1; + operand_t o2; + operand_t o3; +}; -typedef struct { +struct prog_section_both_t { /* * The types: * 0 = ev_void @@ -503,7 +367,7 @@ typedef struct { uint16_t type; uint16_t offset; uint32_t name; -} prog_section_both_t; +}; typedef prog_section_both_t prog_section_def_t; typedef prog_section_both_t prog_section_field_t; @@ -512,7 +376,7 @@ typedef prog_section_both_t prog_section_field_t; #define DEF_SAVEGLOBAL (1<<15) #define DEF_TYPEMASK ((1<<15)-1) -typedef struct { +struct prog_section_function_t { int32_t entry; /* in statement table for instructions */ uint32_t firstlocal; /* First local in local table */ uint32_t locals; /* Total ints of params + locals */ @@ -521,7 +385,7 @@ typedef struct { uint32_t file; /* file of the source file */ int32_t nargs; /* number of arguments */ uint8_t argsize[8]; /* size of arguments (keep 8 always?) */ -} prog_section_function_t; +}; /* * Instructions @@ -627,40 +491,44 @@ enum { /* TODO: elide */ extern const char *util_instr_str[VINSTR_END]; -void util_swap_header (prog_header_t *code_header); -void util_swap_statements (prog_section_statement_t *statements); -void util_swap_defs_fields(prog_section_both_t *section); -void util_swap_functions (prog_section_function_t *functions); -void util_swap_globals (int32_t *globals); +void util_swap_header(prog_header_t &code_header); +void util_swap_statements(std::vector &statements); +void util_swap_defs_fields(std::vector §ion); +void util_swap_functions(std::vector &functions); +void util_swap_globals(std::vector &globals); -typedef float qcfloat_t; -typedef int32_t qcint_t; +typedef float qcfloat_t; +typedef int32_t qcint_t; typedef uint32_t qcuint_t; -typedef struct { - prog_section_statement_t *statements; - int *linenums; - int *columnnums; - prog_section_def_t *defs; - prog_section_field_t *fields; - prog_section_function_t *functions; - int *globals; - char *chars; - uint16_t crc; - uint32_t entfields; - ht string_cache; - qcint_t string_cached_empty; -} code_t; +struct code_t { + void* operator new(std::size_t); + void operator delete(void*); + code_t(); + ~code_t(); + std::vector statements; + std::vector linenums; + std::vector columnnums; + std::vector defs; + std::vector fields; + std::vector functions; + std::vector globals; + std::vector chars; + uint16_t crc = 0; + uint32_t entfields = 0; + ht string_cache; + qcint_t string_cached_empty = 0; +}; /* * A shallow copy of a lex_file to remember where which ast node * came from. */ -typedef struct { +struct lex_ctx_t { const char *file; - size_t line; - size_t column; -} lex_ctx_t; + size_t line; + size_t column; +}; /* * code_write -- writes out the compiled file @@ -699,8 +567,8 @@ enum { LVL_ERROR }; -fs_file_t *con_default_out(void); -fs_file_t *con_default_err(void); +FILE *con_default_out(void); +FILE *con_default_err(void); void con_vprintmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap); void con_printmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, ...); @@ -711,7 +579,6 @@ void con_close (void); void con_init (void); void con_reset (void); 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 *, ...); @@ -722,15 +589,31 @@ extern size_t compile_errors; extern size_t compile_Werrors; extern size_t compile_warnings; -void /********/ compile_error (lex_ctx_t ctx, /*LVL_ERROR*/ const char *msg, ...); +void /********/ compile_error_ (lex_ctx_t ctx, /*LVL_ERROR*/ const char *msg, ...); void /********/ vcompile_error (lex_ctx_t ctx, /*LVL_ERROR*/ const char *msg, va_list ap); -bool GMQCC_WARN compile_warning (lex_ctx_t ctx, int warntype, const char *fmt, ...); +bool GMQCC_WARN compile_warning_(lex_ctx_t ctx, int warntype, const char *fmt, ...); bool GMQCC_WARN vcompile_warning(lex_ctx_t ctx, int warntype, const char *fmt, va_list ap); void compile_show_werrors(void); +template +inline constexpr const T formatNormalize(const T argument) { return argument; } + +inline const char *formatNormalize(const std::string &argument) { + return argument.c_str(); +} + +template +inline bool GMQCC_WARN compile_warning(lex_ctx_t ctx, int warntype, const char *fmt, const Ts&... ts) { + return compile_warning_(ctx, warntype, fmt, formatNormalize(ts)...); +} +template +inline void /********/ compile_error (lex_ctx_t ctx, /*LVL_ERROR*/ const char *msg, const Ts&... ts) { + return compile_error_(ctx, msg, formatNormalize(ts)...); +} + /* ir.c */ /* TODO: cleanup */ -enum store_types { +enum store_type { store_global, store_local, /* local, assignable for now, should get promoted later */ store_param, /* parameters, they are locals with a fixed position */ @@ -738,9 +621,9 @@ enum store_types { store_return /* unassignable, at OFS_RETURN */ }; -typedef struct { +struct vec3_t { qcfloat_t x, y, z; -} vec3_t; +}; /* exec.c */ @@ -777,27 +660,30 @@ enum { #define VMXF_TRACE 0x0001 /* trace: print statements before executing */ #define VMXF_PROFILE 0x0002 /* profile: increment the profile counters */ -struct qc_program_s; -typedef int (*prog_builtin_t)(struct qc_program_s *prog); +typedef struct qc_program qc_program_t; +typedef int (*prog_builtin_t)(qc_program_t *prog); -typedef struct { - qcint_t stmt; - size_t localsp; +struct qc_exec_stack_t { + qcint_t stmt; + size_t localsp; prog_section_function_t *function; -} qc_exec_stack_t; +}; + +struct qc_program { + qc_program() = delete; + qc_program(const char *name, uint16_t crc, size_t entfields); -typedef struct qc_program_s { - char *filename; - prog_section_statement_t *code; - prog_section_def_t *defs; - prog_section_def_t *fields; - prog_section_function_t *functions; - char *strings; - qcint_t *globals; - qcint_t *entitydata; - bool *entitypool; + std::string filename; + std::vector code; + std::vector defs; + std::vector fields; + std::vector functions; + std::vector strings; + std::vector globals; + std::vector entitydata; + std::vector entitypool; - const char* *function_stack; + std::vector function_stack; uint16_t crc16; @@ -806,7 +692,7 @@ typedef struct qc_program_s { qcint_t vmerror; - size_t *profile; + std::vector profile; prog_builtin_t *builtins; size_t builtins_count; @@ -816,14 +702,28 @@ typedef struct qc_program_s { size_t entityfields; bool allowworldwrites; - qcint_t *localstack; - qc_exec_stack_t *stack; + std::vector localstack; + std::vector stack; size_t statement; size_t xflags; int argc; /* current arg count for debugging */ -} qc_program_t; + + /* cached fields */ + struct { + qcint_t frame; + qcint_t nextthink; + qcint_t think; + } cached_fields; + + struct { + qcint_t self; + qcint_t time; + } cached_globals; + + bool supports_state; /* is INSTR_STATE supported? */ +}; qc_program_t* prog_load (const char *filename, bool ignoreversion); void prog_delete (qc_program_t *prog); @@ -832,27 +732,26 @@ const char* prog_getstring (qc_program_t *prog, qcint_t str); prog_section_def_t* prog_entfield (qc_program_t *prog, qcint_t off); prog_section_def_t* prog_getdef (qc_program_t *prog, qcint_t off); qcany_t* prog_getedict (qc_program_t *prog, qcint_t e); -qcint_t prog_tempstring(qc_program_t *prog, const char *_str); +qcint_t prog_tempstring(qc_program_t *prog, const char *_str); /* parser.c */ -struct parser_s; -struct parser_s *parser_create (void); -bool parser_compile_file (struct parser_s *parser, const char *); -bool parser_compile_string(struct parser_s *parser, const char *, const char *, size_t); -bool parser_finish (struct parser_s *parser, const char *); -void parser_cleanup (struct parser_s *parser); +struct parser_t; +parser_t *parser_create(void); +bool parser_compile_file(parser_t *parser, const char *); +bool parser_compile_string(parser_t *parser, const char *, const char *, size_t); +bool parser_finish(parser_t *parser, const char *); /* ftepp.c */ -struct ftepp_s; -struct ftepp_s *ftepp_create (void); -bool ftepp_preprocess_file (struct ftepp_s *ftepp, const char *filename); -bool ftepp_preprocess_string(struct ftepp_s *ftepp, const char *name, const char *str); -void ftepp_finish (struct ftepp_s *ftepp); -const char *ftepp_get (struct ftepp_s *ftepp); -void ftepp_flush (struct ftepp_s *ftepp); -void ftepp_add_define (struct ftepp_s *ftepp, const char *source, const char *name); -void ftepp_add_macro (struct ftepp_s *ftepp, const char *name, const char *value); +struct ftepp_t; +ftepp_t *ftepp_create (void); +bool ftepp_preprocess_file (ftepp_t *ftepp, const char *filename); +bool ftepp_preprocess_string(ftepp_t *ftepp, const char *name, const char *str); +void ftepp_finish(ftepp_t *ftepp); +const char *ftepp_get(ftepp_t *ftepp); +void ftepp_flush(ftepp_t *ftepp); +void ftepp_add_define(ftepp_t *ftepp, const char *source, const char *name); +void ftepp_add_macro(ftepp_t *ftepp, const char *name, const char *value); /* main.c */ @@ -860,10 +759,10 @@ void ftepp_add_macro (struct ftepp_s *ftepp, const char *name, /* Helpers to allow for a whole lot of flags. Otherwise we'd limit * to 32 or 64 -f options... */ -typedef struct { +struct longbit { size_t idx; /* index into an array of 32 bit words */ uint8_t bit; /* bit index for the 8 bit group idx points to */ -} longbit; +}; #define LONGBIT(bit) { ((bit)/32), ((bit)%32) } #define LONGBIT_SET(B, I) ((B).idx = (I)/32, (B).bit = ((I)%32)) #else @@ -878,10 +777,10 @@ int utf8_from(char *, utf8ch_t); int utf8_to(utf8ch_t *, const unsigned char *, size_t); /* opts.c */ -typedef struct { +struct opts_flag_def_t { const char *name; longbit bit; -} opts_flag_def_t; +}; bool opts_setflag (const char *, bool); bool opts_setwarn (const char *, bool); @@ -935,30 +834,27 @@ extern const unsigned int opts_opt_oflag[COUNT_OPTIMIZATIONS+1]; extern unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS]; /* other options: */ -typedef enum { +enum { COMPILER_QCC, /* circa QuakeC */ COMPILER_FTEQCC, /* fteqcc QuakeC */ COMPILER_QCCX, /* qccx QuakeC */ COMPILER_GMQCC /* this QuakeC */ -} opts_std_t; +}; -typedef struct { +struct opt_value_t { union { - bool b; + bool b; uint16_t u16; uint32_t u32; - union { - char *p; + char *p; const char *c; } str; } data; - bool allocated; -} opt_value_t; - +}; -typedef struct { +struct opts_cmd_t { opt_value_t options [OPTION_COUNT]; uint32_t flags [1 + (COUNT_FLAGS / 32)]; uint32_t warn [1 + (COUNT_WARNINGS / 32)]; @@ -967,11 +863,11 @@ typedef struct { uint32_t werror_backup[1 + (COUNT_WARNINGS / 32)]; uint32_t optimization [1 + (COUNT_OPTIMIZATIONS / 32)]; bool optimizeoff; /* True when -O0 */ -} opts_cmd_t; +}; extern opts_cmd_t opts; -#define OPTS_GENERIC(f,i) (!! (((f)[(i)/32]) & (1<< (unsigned)((i)%32)))) +#define OPTS_GENERIC(f,i) (!! (((f)[(i)/32]) & (1U << (unsigned)((i)%32)))) #define OPTS_FLAG(i) OPTS_GENERIC(opts.flags, (i)) #define OPTS_WARN(i) OPTS_GENERIC(opts.warn, (i))