├── EXTENSIONS ├── LICENSE ├── Makefile ├── README.md ├── STANDARD ├── arch_amd64.h ├── arch_dummy.h ├── ast.c ├── ast.h ├── conv.c ├── conv.h ├── decl.c ├── gen.c ├── gen.h ├── gen_amd64.c ├── include ├── alignof.h ├── index.html ├── stdarg.h ├── stdbool.h └── stddef.h ├── index.html ├── init.c ├── init.h ├── lexer.c ├── lexer.h ├── lice.c ├── lice.h ├── lice └── .travis.yml ├── list.c ├── list.h ├── misc ├── argsgen.c └── index.html ├── opt.c ├── opt.h ├── parse.c ├── parse.h ├── test.c ├── testrun.c ├── tests ├── _Bool.c ├── alignof.c ├── args.c ├── arithmetic.c ├── array.c ├── bitwise.c ├── cast.c ├── cgoto.c ├── compare.c ├── compound.c ├── control.c ├── dl.c ├── enum.c ├── es.c ├── extern.c ├── float.c ├── function.c ├── global.c ├── index.html ├── init.c ├── int.c ├── kandr.c ├── line.c ├── literal.c ├── number.c ├── offsetof.c ├── pointer.c ├── returnaddr.c ├── scope.c ├── sizeof.c ├── statica.c ├── struct.c ├── typeof.c ├── types.c ├── union.c ├── varargs.c └── void.c ├── util.c └── util.h /EXTENSIONS: -------------------------------------------------------------------------------- 1 | LICE implements the following extentions that are likewise present 2 | in existing compilers like GCC/Clang. 3 | 4 | - Dollar signs in Identifier Names: 5 | http://gcc.gnu.org/onlinedocs/gcc/Dollar-Signs.html 6 | 7 | - Referring to a Type with typeof: 8 | http://gcc.gnu.org/onlinedocs/gcc/Typeof.html 9 | 10 | - Conditionals with Omitted Operands: 11 | http://gcc.gnu.org/onlinedocs/gcc/Conditionals.html 12 | 13 | - Statements and Declarations in Expressions 14 | http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html 15 | 16 | - Structures with No Members 17 | http://gcc.gnu.org/onlinedocs/gcc/Empty-Structures.html 18 | 19 | - Non-Constant Initializers 20 | http://gcc.gnu.org/onlinedocs/gcc/Initializers.html 21 | 22 | - Case Ranges 23 | http://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html 24 | 25 | - Cast to a Union Type 26 | http://gcc.gnu.org/onlinedocs/gcc/Cast-to-Union.html 27 | 28 | - The Character in Constants 29 | http://gcc.gnu.org/onlinedocs/gcc/Character-Escapes.html 30 | 31 | - Incomplete enum Types 32 | http://gcc.gnu.org/onlinedocs/gcc/Incomplete-Enums.html 33 | 34 | - Binary constants using the '0b' prefix 35 | http://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html 36 | 37 | - Arithmetic on void- and Function-Pointers 38 | http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html 39 | 40 | - Labels as Values 41 | http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html 42 | 43 | - Arrays of Length Zero 44 | http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html 45 | 46 | - Getting the Return or Frame Address of a Function 47 | http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html 48 | __builtin_return_address only currently. 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC ?= clang 2 | CFLAGS += -Wall -Wextra -Wno-missing-field-initializers -O3 -std=c99 -MD -DLICE_TARGET_AMD64 3 | LDFLAGS += 4 | 5 | LICESOURCES = ast.c parse.c lice.c gen.c gen_amd64.c lexer.c util.c conv.c decl.c init.c list.c opt.c 6 | ARGSSOURCES = misc/argsgen.c util.c list.c 7 | TESTSOURCES = test.c util.c list.c 8 | LICEOBJECTS = $(LICESOURCES:.c=.o) 9 | TESTOBJECTS = $(TESTSOURCES:.c=.o) 10 | ARGSOBJECTS = $(ARGSSOURCES:.c=.o) 11 | LICEDEPENDS = $(LICESOURCES:.c=.d) 12 | TESTDEPENDS = $(TESTSOURCES:.c=.d) 13 | ARGSDEPENDS = $(ARGSSOURCES:.c=.d) 14 | LICEBIN = lice 15 | TESTBIN = testsuite 16 | ARGSBIN = argsgenerator 17 | 18 | all: $(LICEBIN) $(TESTBIN) 19 | 20 | $(LICEBIN): $(LICEOBJECTS) 21 | $(CC) $(LDFLAGS) $(LICEOBJECTS) -o $@ 22 | 23 | $(TESTBIN): $(TESTOBJECTS) 24 | $(CC) $(LDFLAGS) $(TESTOBJECTS) -o $@ 25 | 26 | $(ARGSBIN): $(ARGSOBJECTS) 27 | $(CC) $(LDFLAGS) $(ARGSOBJECTS) -o $@ 28 | 29 | c.o: 30 | $(CC) -c $(CFLAGS) $< -o $@ 31 | 32 | args: $(ARGSBIN) 33 | @./$(ARGSBIN) 34 | 35 | clean: 36 | rm -f $(LICEOBJECTS) 37 | rm -f $(TESTOBJECTS) 38 | rm -f $(LICEDEPENDS) 39 | rm -f $(TESTDEPENDS) 40 | rm -f $(ARGSDEPENDS) 41 | rm -f $(LICEBIN) 42 | rm -f $(TESTBIN) 43 | rm -f $(ARGSBIN) 44 | 45 | test: $(LICEBIN) $(TESTBIN) 46 | @./$(TESTBIN) 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DOWNLOADED_FROM='http://gmqcc.qc.to/cgit/cgit.cgi/LICE.git/plain/'; 2 | DOWNLOAD_DATE='17-11-2014'; 3 | HOMEPAGE='http://gmqcc.qc.to/cgit/cgit.cgi/LICE.git/tree/README.md'; 4 | 5 | 6 | ### Epilogue 7 | LICE is a work in progress C99 compiler designed as a solution for 8 | teaching myself and others about the internals of the C programming 9 | language, how to write a compiler for it, and code generation. 10 | 11 | Part of the philosophy behind LICE is to provide a public domain 12 | implementation of a working conformant C99 compiler. As well as borrowing 13 | extensions and ideas from existing compilers to ensure a wider range of 14 | support. 15 | 16 | ### Status 17 | See the STANDARDS file for the status on which standards LICE supports. 18 | 19 | ### Prologue 20 | If you don't find yourself needing any of the stuff which is marked as being 21 | unsupported above then you may find that LICE will happily compile your 22 | source into x86-64 assembly. The code generation is close from optimal. 23 | LICE treats the entire system as a giant stack machine, since it's easier 24 | to generate code that way. The problem is it's hardly efficent. All local 25 | variables are assigned on the stack for operations. All operations operate 26 | from the stack and write back the result to the stack location that is 27 | the destination operand for that operation. 28 | 29 | ### Porting 30 | LICE should be farily straightforward to retarget for a specific architecture 31 | or ABI. Start by making a copy of `arch_dummy.h`, naming it `arch_yourarch.h` 32 | create an entry in `lice.h` for that header guarded by conditional include. 33 | Supply that as a default option in the Makefile, remove `gen_amd64.c` from 34 | the Makefile, add your own to it. Then write the code generator. Documentation 35 | may be found in `gen.h`. 36 | 37 | 38 | ### Future Endeavors 39 | - Full C90 support 40 | 41 | - Full C99 support 42 | 43 | - Full C11 support 44 | 45 | - Preprocessor 46 | 47 | - Intermediate stage with optimizations (libfirm?) 48 | 49 | - Code generation (directly to elf/coff, et. all) 50 | 51 | - Support for x86, ARM, PPC 52 | 53 | ### Sources 54 | The following sources where used in the construction of LICE 55 | 56 | - Aho, Alfred V., and Alfred V. Aho. Compilers: Principles, Techniques, & Tools. Boston: Pearson/Addison Wesley, 2007. Print. 57 | http://www.amazon.ca/Compilers-Principles-Techniques-Alfred-Aho/dp/0201100886 58 | 59 | - Degener, Jutta. "ANSI C Grammar, Lex Specification." ANSI C Grammar (Lex). N.p., 1995. Web. 60 | http://www.lysator.liu.se/c/ANSI-C-grammar-l.html 61 | 62 | - Matz, Michael, Jan Hubicka, Andreas Jaeger, and Mark Mitchell. "System V Application Binary Interface AMD64 Architecture Processor Supplement." N.p., 07 Oct. 2013. Print. 63 | http://www.x86-64.org/documentation/abi.pdf 64 | 65 | - Kahan, W., Prof. "IEEE Standard 754 for Binary Floating-Point Arithmetic." N.p., 1 Oct. 1997. Print. 66 | http://www.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF 67 | 68 | - Crenshaw, Jack. "Let's Build a Compiler." I.E.C.C., 1995. Web. 69 | http://compilers.iecc.com/crenshaw/ 70 | 71 | - "C99 Final Draft." ISO/IEC, 06 May 2006. Print. 72 | http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf 73 | 74 | - "C11 Final Draft." ISO/IEC, 12 April 2011. Print. 75 | http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 76 | 77 | - "Instruction Set Reference, A-Z." Intel 64 and IA-32 Architectures Software Developer's Manual. Vol. 2. [Calif.?]: Intel, 2013. N. pag. Print. 78 | http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf 79 | 80 | - Bendersky, Eli. "Complete C99 parser in pure Python." pycparser. N.p., N.d. Web. 81 | https://github.com/eliben/pycparser 82 | 83 | ### Inspiration 84 | The following projects were seen as inspiration in the construciton of 85 | LICE. 86 | 87 | - SubC 88 | http://www.t3x.org/subc/ 89 | 90 | - TCC 91 | http://bellard.org/tcc/ 92 | 93 | - lcc 94 | https://sites.google.com/site/lccretargetablecompiler/ 95 | 96 | - Kaleidoscope 97 | http://llvm.org/docs/tutorial/index.html 98 | -------------------------------------------------------------------------------- /STANDARD: -------------------------------------------------------------------------------- 1 | The status of language standards in LICE. 2 | 3 | C11 status: 4 | Things supported: 5 | Anonymous structures and unions 6 | Static assertions (_Static_assert) 7 | Things unsupported: 8 | Alignment specification (_Alignas) 9 | _Noreturn function specifier 10 | Type-Generic expressions (_Generic) 11 | 12 | C99 status: 13 | Fully supported with exception to the following things: 14 | - Veriable length arrays 15 | 16 | C90 status: 17 | Fully supported with exception to the following things: 18 | - String concatenation of adjacent strings 19 | - May include C99 feautures by accident (allowing invalid C90 code to compile) 20 | K&R status: 21 | Fully supported with exception to the following things: 22 | - The K&R function definition syntax 23 | 24 | LICE also supports these additional types of C: 25 | 26 | GNUC status: 27 | Small subset of common things supported, see EXTENSIONS for a list. 28 | 29 | LICEC status: 30 | LICEC is C11 with GNUC extensions. 31 | -------------------------------------------------------------------------------- /arch_amd64.h: -------------------------------------------------------------------------------- 1 | #ifndef LICE_ARCH_AMD64_HDR 2 | /* 3 | * File: arch_amd64.h 4 | * Isolates AMD64 / SystemV ABI specific details that are used in 5 | * a variety of places of the compiler to target AMD64. 6 | */ 7 | 8 | /* 9 | * Constants: Native type sizes 10 | * 11 | * The following are macros which describe the sizes of various native 12 | * data types, they should reflect their true sizes on the given 13 | * architecture unless mentioned otherwise by a specific ABI. 14 | * 15 | * ARCH_TYPE_SIZE_CHAR - Size of a char 16 | * ARCH_TYPE_SIZE_LONG - Size of a long 17 | * ARCH_TYPE_SIZE_LLONG - Size of a long long 18 | * ARCH_TYPE_SIZE_INT - Size of a int 19 | * ARCH_TYPE_SIZE_SHORT - Size of a short 20 | * ARCH_TYPE_SIZE_FLOAT - Size of a float 21 | * ARCH_TYPE_SIZE_DOUBLE - Size of a double 22 | * ARCH_TYPE_SIZE_LDOUBLE - Size of a long double 23 | * ARCH_TYPE_SIZE_POINTER - Size of a pointer 24 | */ 25 | #define ARCH_TYPE_SIZE_CHAR 1 26 | #define ARCH_TYPE_SIZE_LONG 8 27 | #define ARCH_TYPE_SIZE_LLONG 8 28 | #define ARCH_TYPE_SIZE_INT 4 29 | #define ARCH_TYPE_SIZE_SHORT 2 30 | #define ARCH_TYPE_SIZE_FLOAT 4 31 | #define ARCH_TYPE_SIZE_DOUBLE 8 32 | #define ARCH_TYPE_SIZE_LDOUBLE 8 33 | #define ARCH_TYPE_SIZE_POINTER 8 34 | 35 | /* 36 | * Macro: ARCH_ALIGNMENT 37 | * The default alignment of structure elements (padding) for the given 38 | * architecture / ABI 39 | */ 40 | #define ARCH_ALIGNMENT 16 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /arch_dummy.h: -------------------------------------------------------------------------------- 1 | #ifndef LICE_ARCH_DUMMY_HDR 2 | /* 3 | * File: arch_dummy.h 4 | * Stubded dummy architecture useful as a template for retargeting 5 | * LICE. 6 | */ 7 | 8 | /* 9 | * Constants: Native type sizes 10 | * 11 | * The following are macros which describe the sizes of various native 12 | * data types, they should reflect their true sizes on the given 13 | * architecture unless mentioned otherwise by a specific ABI. 14 | * 15 | * ARCH_TYPE_SIZE_CHAR - Size of a char 16 | * ARCH_TYPE_SIZE_LONG - Size of a long 17 | * ARCH_TYPE_SIZE_LLONG - Size of a long long 18 | * ARCH_TYPE_SIZE_INT - Size of a int 19 | * ARCH_TYPE_SIZE_SHORT - Size of a short 20 | * ARCH_TYPE_SIZE_FLOAT - Size of a float 21 | * ARCH_TYPE_SIZE_DOUBLE - Size of a double 22 | * ARCH_TYPE_SIZE_LDOUBLE - Size of a long double 23 | * ARCH_TYPE_SIZE_POINTER - Size of a pointer 24 | */ 25 | #define ARCH_TYPE_SIZE_CHAR -1 26 | #define ARCH_TYPE_SIZE_LONG -1 27 | #define ARCH_TYPE_SIZE_LLONG -1 28 | #define ARCH_TYPE_SIZE_INT -1 29 | #define ARCH_TYPE_SIZE_SHORT -1 30 | #define ARCH_TYPE_SIZE_FLOAT -1 31 | #define ARCH_TYPE_SIZE_DOUBLE -1 32 | #define ARCH_TYPE_SIZE_LDOUBLE -1 33 | #define ARCH_TYPE_SIZE_POINTER -1 34 | 35 | /* 36 | * Macro: ARCH_ALIGNMENT 37 | * The default alignment of structure elements (padding) for the given 38 | * architecture / ABI 39 | */ 40 | #define ARCH_ALIGNMENT -1 41 | #endif 42 | -------------------------------------------------------------------------------- /ast.h: -------------------------------------------------------------------------------- 1 | #ifndef LICE_AST_HDR 2 | #define LICE_AST_HDR 3 | #include "util.h" 4 | 5 | /* 6 | * File: ast.h 7 | * Implements the interface to LICE's abstract syntax tree 8 | */ 9 | typedef struct ast_s ast_t; 10 | 11 | /* 12 | * Type: ast_type_t 13 | * The type of ast node 14 | * 15 | * Constants: 16 | * 17 | * AST_TYPE_LITERAL - Literal 18 | * AST_TYPE_STRING - String literal 19 | * AST_TYPE_VAR_LOCAL - Local variable 20 | * AST_TYPE_VAR_GLOBAL - Global variable 21 | * AST_TYPE_CALL - Direct function call 22 | * AST_TYPE_POINTERCALL - Indirect function call 23 | * AST_TYPE_FUNCTION - Function 24 | * AST_TYPE_PROTOTYPE - Prototype 25 | * AST_TYPE_DECLARATION - Declaration 26 | * AST_TYPE_INITIALIZER - Initializer 27 | * AST_TYPE_STRUCT - Structure 28 | * AST_TYPE_ADDRESS - Address of operation 29 | * AST_TYPE_DEREFERENCE - Pointer dereference 30 | * AST_TYPE_EXPRESSION_TERNARY - Ternary expression 31 | * AST_TYPE_EXPRESSION_CAST - Type cast expression 32 | * AST_TYPE_STATEMENT_IF - If statement 33 | * AST_TYPE_STATEMENT_FOR - For statement 34 | * AST_TYPE_STATEMENT_WHILE - While statement 35 | * AST_TYPE_STATEMENT_DO - Do statement 36 | * AST_TYPE_STATEMENT_SWITCH - Switch statement 37 | * AST_TYPE_STATEMENT_CASE - Switch statement case 38 | * AST_TYPE_STATEMENT_DEFAULT - Switch statement default case 39 | * AST_TYPE_STATEMENT_RETURN - Return statement 40 | * AST_TYPE_STATEMENT_BREAK - Break statement 41 | * AST_TYPE_STATEMENT_CONTINUE - Continue statement 42 | * AST_TYPE_STATEMENT_COMPOUND - Compound statement 43 | * AST_TYPE_STATEMENT_GOTO - Goto statement 44 | * AST_TYPE_STATEMENT_LABEL - Goto statement label 45 | * AST_TYPE_POST_INCREMENT - Post increment operation 46 | * AST_TYPE_POST_DECREMENT - Post decrement operation 47 | * AST_TYPE_PRE_INCREMENT - Pre increment operation 48 | * AST_TYPE_PRE_DECREMENT - Pre decrement operation 49 | * AST_TYPE_LSHIFT - Left shift operation 50 | * AST_TYPE_RSHIFT - Right shift operation 51 | * AST_TYPE_LRSHIFT - Logical right shift operation 52 | * AST_TYPE_EQUAL - Equality condition 53 | * AST_TYPE_GEQUAL - Greater-or-equal condition 54 | * AST_TYPE_LEQUAL - Less-or-equal condition 55 | * AST_TYPE_NEQUAL - Not-equal condition 56 | * AST_TYPE_NEGATE - Negation 57 | * AST_TYPE_AND - Logical-and operation 58 | * AST_TYPE_OR - Logical-or operation 59 | * AST_TYPE_NEGATE - Unary minus 60 | * AST_TYPE_VA_START - __builtin_va_start 61 | * AST_TYPE_VA_ARG - __builtin_va_arg 62 | * AST_TYPE_DESIGNATOR - Designation on function types 63 | * AST_TYPE_CONVERT - Type conversion 64 | */ 65 | typedef enum { 66 | AST_TYPE_LITERAL = 0x100, 67 | AST_TYPE_STRING, 68 | AST_TYPE_VAR_LOCAL, 69 | AST_TYPE_VAR_GLOBAL, 70 | AST_TYPE_CALL, 71 | AST_TYPE_POINTERCALL, 72 | AST_TYPE_FUNCTION, 73 | AST_TYPE_PROTOTYPE, 74 | AST_TYPE_DECLARATION, 75 | AST_TYPE_INITIALIZER, 76 | AST_TYPE_STRUCT, 77 | AST_TYPE_ADDRESS, 78 | AST_TYPE_DEREFERENCE, 79 | AST_TYPE_EXPRESSION_TERNARY, 80 | AST_TYPE_EXPRESSION_CAST, 81 | AST_TYPE_STATEMENT_IF, 82 | AST_TYPE_STATEMENT_FOR, 83 | AST_TYPE_STATEMENT_WHILE, 84 | AST_TYPE_STATEMENT_DO, 85 | AST_TYPE_STATEMENT_SWITCH, 86 | AST_TYPE_STATEMENT_CASE, 87 | AST_TYPE_STATEMENT_DEFAULT, 88 | AST_TYPE_STATEMENT_RETURN, 89 | AST_TYPE_STATEMENT_BREAK, 90 | AST_TYPE_STATEMENT_CONTINUE, 91 | AST_TYPE_STATEMENT_COMPOUND, 92 | AST_TYPE_STATEMENT_GOTO, 93 | AST_TYPE_STATEMENT_LABEL, 94 | AST_TYPE_STATEMENT_GOTO_COMPUTED, 95 | AST_TYPE_STATEMENT_LABEL_COMPUTED, 96 | AST_TYPE_POST_INCREMENT, 97 | AST_TYPE_POST_DECREMENT, 98 | AST_TYPE_PRE_INCREMENT, 99 | AST_TYPE_PRE_DECREMENT, 100 | AST_TYPE_LSHIFT, 101 | AST_TYPE_RSHIFT, 102 | AST_TYPE_LRSHIFT, 103 | AST_TYPE_EQUAL, 104 | AST_TYPE_GEQUAL, 105 | AST_TYPE_LEQUAL, 106 | AST_TYPE_NEQUAL, 107 | AST_TYPE_NEGATE, 108 | AST_TYPE_AND, 109 | AST_TYPE_OR, 110 | AST_TYPE_VA_START, 111 | AST_TYPE_VA_ARG, 112 | AST_TYPE_DESIGNATOR, 113 | AST_TYPE_CONVERT, 114 | } ast_type_t; 115 | 116 | 117 | /* 118 | * Type: type_t 119 | * Type describing the ast type. 120 | * 121 | * Constants: 122 | * 123 | * TYPE_VOID - void 124 | * TYPE_BOOL - boolean 125 | * TYPE_CHAR - char 126 | * TYPE_SHORT - short 127 | * TYPE_INT - int 128 | * TYPE_LONG - long 129 | * TYPE_LLONG - long long 130 | * TYPE_DOUBLE - double 131 | * TYPE_LDOUBLE - long double 132 | * TYPE_ARRAY - array (also contains a type_t for base type) 133 | * TYPE_POINTER - pointer (also contains a type_t for base type) 134 | * TYPE_STRUCTURE - structure (user defined) 135 | * TYPE_FUNCTION - function (user defined) 136 | * TYPE_CDECL - used by the parser for dealing with declarations 137 | */ 138 | typedef enum { 139 | TYPE_VOID, 140 | TYPE_BOOL, 141 | TYPE_CHAR, 142 | TYPE_SHORT, 143 | TYPE_INT, 144 | TYPE_LONG, 145 | TYPE_LLONG, 146 | TYPE_FLOAT, 147 | TYPE_DOUBLE, 148 | TYPE_LDOUBLE, 149 | TYPE_ARRAY, 150 | TYPE_POINTER, 151 | TYPE_STRUCTURE, 152 | TYPE_FUNCTION, 153 | TYPE_CDECL 154 | } type_t; 155 | 156 | /* 157 | * Type: ast_data_type_t 158 | * Type describing the indice into `ast_data_table` 159 | * 160 | * Constants: 161 | * 162 | * AST_DATA_VOID - void 163 | * AST_DATA_BOOL - boolean 164 | * AST_DATA_LONG - long 165 | * AST_DATA_LLONG - long long 166 | * AST_DATA_INT - int 167 | * AST_DATA_SHORT - short 168 | * AST_DATA_CHAR - char 169 | * AST_DATA_FLOAT - float 170 | * AST_DATA_DOUBLE - double 171 | * AST_DATA_LDOUBLE - long double 172 | * AST_DATA_ULONG - unsigned long 173 | * AST_DATA_ULLONG - unsigned long long 174 | * AST_DATA_FUNCTION - function (current) 175 | */ 176 | typedef enum { 177 | AST_DATA_VOID, 178 | AST_DATA_BOOL, 179 | AST_DATA_LONG, 180 | AST_DATA_LLONG, 181 | AST_DATA_INT, 182 | AST_DATA_SHORT, 183 | AST_DATA_CHAR, 184 | AST_DATA_FLOAT, 185 | AST_DATA_DOUBLE, 186 | AST_DATA_LDOUBLE, 187 | AST_DATA_ULONG, 188 | AST_DATA_ULLONG, 189 | AST_DATA_FUNCTION, 190 | AST_DATA_COUNT 191 | } ast_data_type_t; 192 | 193 | /* 194 | * Type: cdecl_t 195 | * Describes type of declarations 196 | * 197 | * Constants: 198 | * 199 | * CDECL_BODY - function body 200 | * CDECL_PARAMETER - parameters (with name) 201 | * CDECL_TYPEONLY - parameters (without name) 202 | * CDECL_CAST - cast 203 | */ 204 | typedef enum { 205 | CDECL_BODY = 1, 206 | CDECL_PARAMETER, 207 | CDECL_TYPEONLY, 208 | CDECL_CAST 209 | } cdecl_t; 210 | 211 | /* 212 | * Type: storage_t 213 | * Describes the storage class for a given variable 214 | * 215 | * Constants: 216 | * 217 | * STORAGE_TYPEDEF - typedef to another type 218 | * STORAGE_EXTERN - external linkage 219 | * STORAGE_STATIC - static storage 220 | * STORAGE_AUTO - automatic storage (implicit) 221 | * STORAGE_REGISTER - make use of register for storage 222 | */ 223 | typedef enum { 224 | STORAGE_TYPEDEF = 1, 225 | STORAGE_EXTERN, 226 | STORAGE_STATIC, 227 | STORAGE_AUTO, 228 | STORAGE_REGISTER 229 | } storage_t; 230 | 231 | /* 232 | * Struct: data_type_t 233 | * A structure that describes a data type. 234 | */ 235 | typedef struct data_type_s data_type_t; 236 | struct data_type_s { 237 | /* 238 | * Variable: type 239 | * The type of the data type. 240 | * 241 | * See Constants for a list of 242 | * valid constant values. 243 | */ 244 | type_t type; 245 | 246 | /* 247 | * Variable: size 248 | * The size of the given data type, this is often the value 249 | * provided for the given type in arch_[target].h 250 | */ 251 | int size; 252 | 253 | /* 254 | * Variable: sign 255 | * Describes if the type is signed or unsigned. 256 | */ 257 | bool sign; 258 | 259 | /* 260 | * Variable: isstatic 261 | * Describes if the type is static. 262 | */ 263 | bool isstatic; 264 | 265 | /* 266 | * Variable: length 267 | * Instances of the data type. 268 | * 269 | * When used as a base-type, i.e not an array; this will be 270 | * 1, otherwise it will be the length of the array, or -1 271 | * if the size of the array is unknown. 272 | */ 273 | int length; 274 | 275 | /* 276 | * Variable: pointer 277 | * When the variable is a pointer type, this will point to another 278 | * data type that describes the base type of the pointer, NULL other- 279 | * wise. 280 | */ 281 | data_type_t *pointer; 282 | 283 | /* structure */ 284 | struct { 285 | /* 286 | * Variable: fields 287 | * Pointer to a table of fields (if structure) 288 | */ 289 | table_t *fields; 290 | 291 | /* 292 | * Variable: offset 293 | * Offset of the given field in a structure (if a structure base type) 294 | */ 295 | int offset; 296 | 297 | /* 298 | * Variable: isstruct 299 | * If we're dealing with a structure this will be true, false 300 | * otherwise. 301 | */ 302 | bool isstruct; 303 | 304 | /* bitfields */ 305 | struct { 306 | int offset; 307 | int size; 308 | } bitfield; 309 | 310 | }; 311 | 312 | /* function */ 313 | struct { 314 | /* 315 | * Variable: returntype 316 | * Pointer to a data type which describes the return type 317 | * of the function (if a function) 318 | */ 319 | data_type_t *returntype; 320 | 321 | /* 322 | * Variable: parameters 323 | * Pointer to a list of parameters for a function. 324 | */ 325 | list_t *parameters; 326 | 327 | /* 328 | * Variable: hasdots 329 | * Describes if the given function is variable-argument. 330 | * 331 | * Contains the value `true` when the function has 332 | * three dots `...` in it's prototype, otherwise `false`. 333 | */ 334 | bool hasdots; 335 | }; 336 | }; 337 | 338 | /* 339 | * Struct: ast_string_t 340 | * The *AST_TYPE_STRING* ast node. 341 | */ 342 | typedef struct { 343 | /* 344 | * Variable: data 345 | * String contents 346 | */ 347 | char *data; 348 | 349 | /* 350 | * Variable: label 351 | * Name of the label associated with the string. 352 | */ 353 | char *label; 354 | } ast_string_t; 355 | 356 | /* 357 | * Struct: ast_variable_t 358 | * The *AST_TYPE_VAR_LOCAL* and *AST_TYPE_VAR_GLOBAL* ast node. 359 | */ 360 | typedef struct { 361 | /* 362 | * Variable: name 363 | * Name of the variable 364 | */ 365 | char *name; 366 | 367 | /* 368 | * Variable: off 369 | * Offset of the variable on the stack. 370 | */ 371 | int off; 372 | 373 | /* 374 | * Variable: label 375 | * Name of the label associated with the variable. 376 | */ 377 | char *label; 378 | 379 | /* 380 | * Variable: init 381 | * Compound literal list for initialization 382 | */ 383 | list_t *init; 384 | } ast_variable_t; 385 | 386 | /* 387 | * Struct ast_function_call_t 388 | * Function call 389 | * 390 | * Remarks: 391 | * Not associated with any node. Instead describes the 392 | * data associated with a function call for *ast_function_t* 393 | */ 394 | typedef struct { 395 | /* 396 | * Variable: args 397 | * Pointer to a list of arguments for a function call 398 | */ 399 | list_t *args; 400 | 401 | /* 402 | * Variable: type 403 | * The basetype of the function that is being called. This type 404 | * is the 'function type', ie. accessing the returntype member of 405 | * this will return the FUNCTIONS return type. 406 | */ 407 | data_type_t *type; 408 | 409 | /* 410 | * Variable: functionpointer 411 | * Pointer to function for function pointer call. 412 | * 413 | * Remarks: 414 | * This only associates with AST_TYPE_POINTERCALL, in which this 415 | * node is filled with the function in which to call by indirection 416 | * (address). 417 | */ 418 | ast_t *functionpointer; 419 | } ast_function_call_t; 420 | 421 | /* 422 | * Struct: ast_function_t 423 | * The *AST_TYPE_FUNCTION* ast node. 424 | */ 425 | typedef struct { 426 | /* 427 | * Variable: name 428 | * The function name 429 | */ 430 | char *name; 431 | 432 | /* 433 | * Variable: call 434 | * Data associated with a function call. 435 | */ 436 | ast_function_call_t call; 437 | 438 | /* 439 | * Variable: params 440 | * Pointer to a list of parameters. 441 | */ 442 | list_t *params; 443 | 444 | /* 445 | * Variable: locals 446 | * Pointer to a list of locals. 447 | */ 448 | list_t *locals; 449 | 450 | /* 451 | * Variable: body 452 | * Pointer to an ast node which describes the body. 453 | * 454 | * Remarks: 455 | * A body is usually composed of a serise of ast nodes, 456 | * typically a compound expression, but could also contain 457 | * nested compound expressions. Think of this as a pointer 458 | * to the head of the beginning of a serise of basic-blocks 459 | * which are the forming of the function body. 460 | */ 461 | ast_t *body; 462 | } ast_function_t; 463 | 464 | /* 465 | * Struct: ast_unary_t 466 | * Represents a unary operation in the AST tree 467 | */ 468 | typedef struct { 469 | /* 470 | * Variable: operand 471 | * Pointer to the operand the unary operation is to 472 | * be performed on. 473 | */ 474 | ast_t *operand; 475 | } ast_unary_t; 476 | 477 | /* 478 | * Struct: ast_decl_t 479 | * Represents a declaration in the AST tree 480 | */ 481 | typedef struct { 482 | /* 483 | * Variable: var 484 | * Pointer to the variable node associated with the 485 | * declaration. 486 | */ 487 | ast_t *var; 488 | 489 | /* 490 | * Variable: init 491 | * When the declaration includes an initialization this points 492 | * to a initlization list. 493 | */ 494 | list_t *init; 495 | } ast_decl_t; 496 | 497 | /* 498 | * Struct: ast_ifthan_t 499 | * Represents a if-than node in the AST tree. 500 | * 501 | * Remarks: 502 | * Describes a two-branch gaurded by conditional test node in the AST 503 | * tree for implementing ternary expressions and if statements. 504 | */ 505 | typedef struct { 506 | /* 507 | * Variable: cond 508 | * The condition node 509 | */ 510 | ast_t *cond; 511 | 512 | /* 513 | * Variable: then 514 | * Basic block for truth path in branch 515 | */ 516 | ast_t *then; 517 | 518 | /* 519 | * Variable: last 520 | * Basic block for false path in branch 521 | */ 522 | ast_t *last; 523 | } ast_ifthan_t; 524 | 525 | /* 526 | * Struct: ast_for_t 527 | * Represents a for-loop node in the AST tree. 528 | * 529 | * Remarks: 530 | * Standard for loop with precondition / initilization expression, 531 | * conditionally testsed, and post step / expression, ergo 532 | * for(init; cond; step) body; 533 | */ 534 | typedef struct { 535 | /* Variable: init */ 536 | ast_t *init; 537 | /* Variable: cond */ 538 | ast_t *cond; 539 | /* Variable: step */ 540 | ast_t *step; 541 | /* Variable: body */ 542 | ast_t *body; 543 | } ast_for_t; 544 | 545 | 546 | /* 547 | * Struct: ast_init_t 548 | * Represents an initializer in the AST tree. 549 | * 550 | * Remarks: 551 | * Represents array initializer lists, as well as aggregate initializer 552 | * lists for structure, enum and union. Also represents a designated 553 | * initializer for a structure. 554 | */ 555 | typedef struct { 556 | /* Variable: value */ 557 | ast_t *value; 558 | 559 | /* Variable: offset */ 560 | int offset; 561 | 562 | /* Variable: type */ 563 | data_type_t *type; 564 | } ast_init_t; 565 | 566 | /* 567 | * Struct: ast_switch_t 568 | * Represents a switch statement in the AST tree. 569 | */ 570 | typedef struct { 571 | /* Variable: expr */ 572 | ast_t *expr; 573 | /* Variable: body */ 574 | ast_t *body; 575 | } ast_switch_t; 576 | 577 | /* 578 | * Struct: ast_goto_t 579 | * Represents a goto statement (or label) in the AST tree. 580 | */ 581 | typedef struct { 582 | /* 583 | * Variable: label 584 | * When not used as a goto statement, describes the name of a label 585 | * that may be 'gone to' with 'goto' 586 | */ 587 | char *label; 588 | 589 | /* 590 | * Variable: where 591 | * Where to go (label wise) for a goto statement. 592 | */ 593 | char *where; 594 | } ast_goto_t; 595 | 596 | /* 597 | * Struct: ast_t 598 | * The monolthic ast tree and node at the same time. 599 | * 600 | * Remarks: 601 | * The ast tree is just a doubly-linked list of ast nodes which are 602 | * capable of being all the possible ast nodes at once. This is 603 | * acomplished with a rather large union of all ast nodes. The only 604 | * thing that declares what a node actually is, is the nodes type 605 | * member. This is beneficial to keeping the complexity of the AST 606 | * tree down, while also keeping memory footprint low. One more 607 | * interesting aspect of this is the ability to have the AST tree 608 | * nodes (next, prev), which make up the doubly-linked list part 609 | * of the same union, giving us a free way to terminate the tree 610 | * without using additional space to determine it. 611 | */ 612 | struct ast_s { 613 | int type; 614 | data_type_t *ctype; 615 | 616 | union { 617 | struct { 618 | int casebeg; 619 | int caseend; 620 | }; 621 | 622 | long integer; 623 | char character; 624 | ast_string_t string; 625 | ast_variable_t variable; 626 | ast_function_t function; 627 | ast_unary_t unary; 628 | ast_decl_t decl; 629 | ast_ifthan_t ifstmt; 630 | ast_for_t forstmt; 631 | ast_switch_t switchstmt; 632 | ast_t *returnstmt; 633 | list_t *compound; 634 | ast_init_t init; 635 | ast_goto_t gotostmt; 636 | ast_t *ap; 637 | 638 | struct { 639 | ast_t *left; 640 | ast_t *right; 641 | }; 642 | 643 | struct { 644 | ast_t *structure; 645 | char *field; 646 | data_type_t *fieldtype; 647 | }; 648 | 649 | struct { 650 | double value; 651 | char *label; 652 | } floating; 653 | }; 654 | }; 655 | 656 | extern data_type_t *ast_data_table[AST_DATA_COUNT]; 657 | 658 | extern list_t *ast_locals; 659 | extern list_t *ast_gotos; 660 | extern table_t *ast_globalenv; 661 | extern table_t *ast_localenv; 662 | extern table_t *ast_structures; 663 | extern table_t *ast_unions; 664 | extern table_t *ast_labels; 665 | 666 | /* 667 | * Function: ast_structure_reference 668 | * Creates an structure reference of a given type for a given field 669 | * 670 | * Parameters: 671 | * type - The type of the field for reference 672 | * structure - The structure that contains said field to be referenced 673 | * name - The name of the field in that structure to reference 674 | * 675 | * Returns: 676 | * An ast node referencing that field in that paticular structure on 677 | * success, otherwise NULL. 678 | */ 679 | ast_t *ast_structure_reference(data_type_t *type, ast_t *structure, char *name); 680 | 681 | /* 682 | * Function: ast_structure_new 683 | * Creates a structure data type 684 | * 685 | * Parameters; 686 | * field - A table of data_type_t fields for the structure 687 | * size - The size of the structure 688 | * isstruct - true if structure, false if structure-like 689 | * 690 | * Returns: 691 | * A new structure data type with the specified fields and size on 692 | * success, NULL otherwise. 693 | */ 694 | data_type_t *ast_structure_new(table_t *fields, int size, bool isstruct); 695 | 696 | 697 | ast_t *ast_new_unary(int type, data_type_t *data, ast_t *operand); 698 | ast_t *ast_new_binary(data_type_t *ctype, int type, ast_t *left, ast_t *right); 699 | ast_t *ast_new_integer(data_type_t *type, int value); 700 | ast_t *ast_new_floating(data_type_t *, double value); 701 | ast_t *ast_new_char(char value); 702 | ast_t *ast_new_string(char *value); 703 | ast_t *ast_new_label(char *); 704 | 705 | char *ast_label(void); 706 | 707 | ast_t *ast_declaration(ast_t *var, list_t *init); 708 | ast_t *ast_variable_local(data_type_t *type, char *name); 709 | ast_t *ast_variable_global(data_type_t *type, char *name); 710 | ast_t *ast_call(data_type_t *type, char *name, list_t *args); 711 | ast_t *ast_pointercall(ast_t *ast, list_t *args); 712 | ast_t *ast_function(data_type_t *type, char *name, list_t *params, ast_t *body, list_t *locals); 713 | ast_t *ast_initializer(ast_t *, data_type_t *, int); 714 | ast_t *ast_if(ast_t *cond, ast_t *then, ast_t *last); 715 | ast_t *ast_for(ast_t *init, ast_t *cond, ast_t *step, ast_t *body); 716 | ast_t *ast_while(ast_t *cond, ast_t *body); 717 | ast_t *ast_do(ast_t *cond, ast_t *body); 718 | ast_t *ast_return(ast_t *val); 719 | ast_t *ast_compound(list_t *statements); 720 | ast_t *ast_ternary(data_type_t *type, ast_t *cond, ast_t *then, ast_t *last); 721 | ast_t *ast_switch(ast_t *expr, ast_t *body); 722 | ast_t *ast_case(int begin, int end); 723 | ast_t *ast_goto(char *); 724 | ast_t *ast_goto_computed(ast_t *expression); 725 | ast_t *ast_label_address(char *); 726 | ast_t *ast_make(int type); 727 | 728 | ast_t *ast_va_start(ast_t *); 729 | ast_t *ast_va_arg(data_type_t *, ast_t*); 730 | 731 | ast_t *ast_designator(char *name, ast_t *func); 732 | 733 | data_type_t *ast_prototype(data_type_t *returntype, list_t *paramtypes, bool dots); 734 | data_type_t *ast_pointer(data_type_t *type); 735 | data_type_t *ast_array(data_type_t *type, int size); 736 | data_type_t *ast_array_convert(data_type_t *ast); 737 | data_type_t *ast_result_type(int operation, data_type_t *); 738 | 739 | ast_t *ast_designator_convert(ast_t *ast); 740 | 741 | bool ast_struct_compare(data_type_t *a, data_type_t *b); 742 | 743 | /* 744 | * Function: ast_type_string 745 | * Get the type of a data_type_t as a string. 746 | */ 747 | const char *ast_type_string(data_type_t *type); 748 | 749 | /* 750 | * Function: ast_type_isinteger 751 | * Check if a given data type is an integral type. 752 | * 753 | * Parameters: 754 | * type - pointer to the data_type_t object to check 755 | * 756 | * Returns: 757 | * true if *type* is integral type, false otherwise. 758 | * 759 | * Remarks: 760 | * Integral includes any of the following data types: 761 | * - TYPE_CHAR 762 | * - TYPE_INT 763 | * - TYPE_SHORT 764 | * - TYPE_LONG 765 | * - TYPE_LLONG 766 | */ 767 | bool ast_type_isinteger(data_type_t *type); 768 | 769 | /* 770 | * Function: ast_type_isfloating 771 | * Check if a given data type is a floating-point one. 772 | * 773 | * Parameters: 774 | * type - pointer to the data_type_t object to check 775 | * 776 | * Returns: 777 | * true if *type* is floating point, false otherwise. 778 | * 779 | * Remarks: 780 | * Floating-point includes any of the following data types 781 | * - TYPE_FLOAT 782 | * - TYPE_DOUBLE 783 | * - TYPE_LDOUBLE 784 | */ 785 | bool ast_type_isfloating(data_type_t *type); 786 | 787 | /* 788 | * Function: ast_type_isstring 789 | * Check if a given data type is string 790 | * 791 | * Parameters: 792 | * type - pointer to the data_type object to check 793 | * 794 | * Returns: 795 | * trye if *type* is a string type, false otherwise. 796 | * 797 | * Remarks: 798 | * string type is determined if it's an array and the base 799 | * type of that array (when decayed to pointer type) is 800 | * TYPE_CHAR 801 | */ 802 | bool ast_type_isstring(data_type_t *type); 803 | 804 | data_type_t *ast_type_copy(data_type_t *type); 805 | data_type_t *ast_type_copy_incomplete(data_type_t *type); 806 | data_type_t *ast_type_create(type_t type, bool sign); 807 | data_type_t *ast_type_stub(void); 808 | 809 | ast_t *ast_type_convert(data_type_t *type, ast_t *ast); 810 | 811 | 812 | char *ast_string(ast_t *ast); 813 | 814 | #endif 815 | -------------------------------------------------------------------------------- /conv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The complicated C rule set for type conversion. This is a full research 3 | * oriented approach, run against the standard, and the tons of trial and 4 | * error. 5 | * 6 | * A little bit about what is involed in type conversion: 7 | * - Arithmetic type rules 8 | * - Implicit conversion 9 | * - Explicit conversion 10 | * 11 | * 1. Arithmetic type rules: 12 | * The C standard defines a set of rules about arithmetic type 13 | * conversion, known as the conversion rank rules, which 14 | * essentially dictate which sides of an expression need to be 15 | * converted. 16 | * 17 | * First rule: 18 | * If the left hand side of an expression isn't an arithmetic type 19 | * or the right hand side of an expression isn't an arithmetic type 20 | * no conversion takes place. 21 | * 22 | * Second rule: 23 | * If the conversion rank of the left hand side expression type 24 | * is less than the conversion rank of the right hand side 25 | * expression type, then the left hand side of that expressions type 26 | * gets converted to the right hands type. 27 | * 28 | * Third rule: 29 | * If the conversion rank of the left hand expression type doesn't 30 | * compare equal to the right hands type, then the right hand side of 31 | * that expressions type gets converted to the left hands type. 32 | * 33 | * Last rule: 34 | * If none of the above applies, then nothing is subjected to conversion, 35 | * and doesn't need to be converted, unless the following: 36 | * 37 | * The binary expression in which each operand is associated with happens 38 | * to be of a relational one in which case the type is converted to 39 | * integer type. 40 | * 41 | * The expression happens to be of array type, in which case the array 42 | * decays to a pointer of it's base type. 43 | * 44 | * 2. Implicit conversion 45 | * Implicit type conversion takes place in two senarios, 1, when 46 | * conversion ranking is involved (promoted types), or when the 47 | * subject of a shift operation where the larger types is always 48 | * assumed to satisfy the shift operation. 49 | * 50 | * 3. Explicit conversion 51 | * The type which is assumed in explicit conversion (casting) is 52 | * the type in which the operand is converted to, unless the conversion 53 | * isn't legal (vector -> scalar for instance) 54 | */ 55 | #include "ast.h" 56 | #include "lice.h" 57 | 58 | bool conv_capable(data_type_t *type) { 59 | return ast_type_isinteger(type) || ast_type_isfloating(type); 60 | } 61 | 62 | int conv_rank(data_type_t *type) { 63 | if (!conv_capable(type)) 64 | goto error; 65 | 66 | switch (type->type) { 67 | case TYPE_BOOL: return 0; 68 | case TYPE_CHAR: return 1; 69 | case TYPE_SHORT: return 2; 70 | case TYPE_INT: return 3; 71 | case TYPE_LONG: return 4; 72 | case TYPE_LLONG: return 5; 73 | case TYPE_FLOAT: return 6; 74 | case TYPE_DOUBLE: return 7; 75 | case TYPE_LDOUBLE: return 8; 76 | default: 77 | goto error; 78 | } 79 | 80 | error: 81 | compile_ice("conv_rank"); 82 | } 83 | 84 | data_type_t *conv_senority(data_type_t *lhs, data_type_t *rhs) { 85 | return conv_rank(lhs) < conv_rank(rhs) ? rhs : lhs; 86 | } 87 | 88 | ast_t *conv_usual(int operation, ast_t *left, ast_t *right) { 89 | if (!conv_capable(left->ctype) || !conv_capable(right->ctype)) { 90 | data_type_t *result; 91 | switch (operation) { 92 | case AST_TYPE_LEQUAL: 93 | case AST_TYPE_GEQUAL: 94 | case AST_TYPE_EQUAL: 95 | case AST_TYPE_NEQUAL: 96 | case '<': 97 | case '>': 98 | result = ast_data_table[AST_DATA_INT]; 99 | break; 100 | default: 101 | result = ast_array_convert(left->ctype); 102 | break; 103 | } 104 | 105 | return ast_new_binary(result, operation, left, right); 106 | } 107 | 108 | int lrank = conv_rank(left->ctype); 109 | int rrank = conv_rank(right->ctype); 110 | 111 | if (lrank < rrank) 112 | left = ast_type_convert(right->ctype, left); 113 | else if (lrank != rrank) 114 | right = ast_type_convert(left->ctype, right); 115 | 116 | data_type_t *result = ast_result_type(operation, left->ctype); 117 | return ast_new_binary(result, operation, left, right); 118 | } 119 | -------------------------------------------------------------------------------- /conv.h: -------------------------------------------------------------------------------- 1 | #ifndef LICE_CONV_HDR 2 | #define LICE_CONV_HDR 3 | 4 | /* 5 | * File: conv.h 6 | * Implements the interface to LICE's type conversion. 7 | */ 8 | #include "ast.h" 9 | 10 | /* 11 | * Function: conv_capable 12 | * Determines if type conversion is capable for a given type. 13 | * 14 | * Parameters: 15 | * type - The type to test for conversion capability 16 | * 17 | * Returns: 18 | * `true` if conversion is capable, `false` otherwise. 19 | */ 20 | bool conv_capable(data_type_t *type); 21 | 22 | /* 23 | * Function: conv_senority 24 | * Determines the senority of two types in question, returning the 25 | * one which out ranks the other. This is usually used in binary 26 | * operations, thus the naming of lhs and rhs are used. 27 | * 28 | * Parameters: 29 | * lhs - Left hand side type 30 | * rhs - Right hand side type 31 | * 32 | * Returns: 33 | * `lhs` if outranks `rhs`, otherwise `rhs` 34 | */ 35 | data_type_t *conv_senority(data_type_t *lhs, data_type_t *rhs); 36 | 37 | /* 38 | * Function: conv_rank 39 | * Determines the conversion ranking of a given data type. 40 | * 41 | * Parameters: 42 | * type - The type to get the conversion ranking of. 43 | * 44 | * Returns: 45 | * An integer value of the conversion ranking of the given data type, 46 | * which can be used in the process of typicla relational, or comparitive 47 | * checks. 48 | */ 49 | int conv_rank(data_type_t *type); 50 | 51 | /* 52 | * Function: conv_usual 53 | * Given a binary operation and the two operands, this will perform 54 | * usualy type conversion and return an ast node that signifies that 55 | * operation (including the conversion). 56 | * 57 | * Parameters: 58 | * operation - An ast type, or character literal for typical binary 59 | * operations, like '+'. 60 | * left - The left hand side of the expression. 61 | * right - The right hand side of the expression. 62 | */ 63 | ast_t *conv_usual(int operation, ast_t *left, ast_t *right); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /decl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Deals with all the complexity in C's declaration specification with 3 | * a rather large state machine model. C has a lot of ways to specify 4 | * something, that happens to be equivlant to other meanings, which are 5 | * also used. This state machine monitors the occurance of certain 6 | * identifiers to build a serise of on/off state which ultimatly 7 | * allows us to disambiguate the meaning, while at the same time enforcing 8 | * correctness. 9 | * 10 | * For instance it isn't legal in C to have a typedef of a 'signed' size 11 | * specified type, than use that typedef with another size specifier. 12 | * More of these rules apply as well, and are documented in the state 13 | * machine set logic. 14 | * 15 | * Once the state machine has completed it's work the get function uses 16 | * the state of the machine to determine what type to return from the 17 | * ast data table for types, or if there needs to be a new type created 18 | * to compensate for the declaration. Similarly at this stage the state 19 | * can be invalid (if something wen terribly wrong) and we can handle, 20 | * or ice. 21 | * 22 | * The main entry point is decl_spec and it's called from the parser, 23 | * if everything passes the callsite gets a data_type_t of the type 24 | * specified. 25 | */ 26 | #include 27 | 28 | #include "parse.h" 29 | #include "lice.h" 30 | #include "lexer.h" 31 | 32 | typedef enum { 33 | SPEC_TYPE_NULL, 34 | SPEC_TYPE_VOID, 35 | SPEC_TYPE_BOOL, 36 | SPEC_TYPE_CHAR, 37 | SPEC_TYPE_INT, 38 | SPEC_TYPE_FLOAT, 39 | SPEC_TYPE_DOUBLE, 40 | } spec_type_t; 41 | 42 | typedef enum { 43 | SPEC_SIZE_NULL, 44 | SPEC_SIZE_SHORT, 45 | SPEC_SIZE_LONG, 46 | SPEC_SIZE_LLONG 47 | } spec_size_t; 48 | 49 | typedef enum { 50 | SPEC_SIGN_NULL, 51 | SPEC_SIGN_SIGNED, 52 | SPEC_SIGN_UNSIGNED 53 | } spec_sign_t; 54 | 55 | static const char *spec_type_string[] = { 56 | "null", "void", "_Bool", "char", 57 | "int", "float", "double" 58 | }; 59 | 60 | static const char *spec_size_string[] = { 61 | "null", "short", "long", "long long" 62 | }; 63 | 64 | static const char *spec_sign_string[] = { 65 | "null", "signed", "unsigned" 66 | }; 67 | 68 | static const char *spec_var_string[] = { 69 | "null", "type", "size", "sign", "user" 70 | }; 71 | 72 | typedef struct { 73 | storage_t class; 74 | spec_type_t type; 75 | spec_size_t size; 76 | spec_sign_t sign; 77 | data_type_t *user; 78 | bool kconst; 79 | bool kvolatile; 80 | bool kinline; 81 | } decl_spec_t; 82 | 83 | typedef enum { 84 | SPEC_VAR_NULL, 85 | SPEC_VAR_TYPE, 86 | SPEC_VAR_SIZE, 87 | SPEC_VAR_SIGN, 88 | SPEC_VAR_USER 89 | } decl_var_t; 90 | 91 | #define decl_spec_error(X, SELECT) \ 92 | decl_spec_error_impl((X), (SELECT), __LINE__) 93 | 94 | static const char *debug_storage_string(const storage_t class) { 95 | switch (class) { 96 | case STORAGE_AUTO: return "auto"; 97 | case STORAGE_EXTERN: return "extern"; 98 | case STORAGE_REGISTER: return "register"; 99 | case STORAGE_STATIC: return "static"; 100 | case STORAGE_TYPEDEF: return "typedef"; 101 | } 102 | return "default"; 103 | } 104 | 105 | static void decl_spec_error_impl(const decl_spec_t *spec, const decl_var_t select, const size_t line) { 106 | const char *type = spec_type_string[spec->type]; 107 | const char *size = spec_size_string[spec->size]; 108 | const char *sign = spec_sign_string[spec->sign]; 109 | const char *var = spec_var_string[select]; 110 | 111 | if (!type) type = "unspecified"; 112 | if (!size) size = "unspecified"; 113 | if (!sign) sign = "unspecified"; 114 | if (!var) var = "unspecified"; 115 | 116 | compile_ice("declaration specifier error %d\n" 117 | "debug info:\n" 118 | " select: %s\n" 119 | " class: %s\n" 120 | " type: %s\n" 121 | " size: %s\n" 122 | " sign: %s\n" 123 | " const: %s\n" 124 | " volatile: %s\n" 125 | " inline: %s\n", 126 | line, 127 | var, 128 | debug_storage_string(spec->class), 129 | type, 130 | size, 131 | sign, 132 | bool_string(spec->kconst), 133 | bool_string(spec->kvolatile), 134 | bool_string(spec->kinline) 135 | ); 136 | } 137 | 138 | static void decl_spec_class(decl_spec_t *spec, const storage_t class) { 139 | if (spec->class != 0) 140 | decl_spec_error(spec, SPEC_VAR_NULL); 141 | spec->class = class; 142 | } 143 | 144 | static void decl_spec_set(decl_spec_t *spec, const decl_var_t select, void *value) { 145 | switch (select) { 146 | case SPEC_VAR_SIGN: 147 | if (spec->sign != SPEC_SIGN_NULL) 148 | decl_spec_error(spec, select); 149 | spec->sign = *(spec_sign_t*)value; 150 | break; 151 | case SPEC_VAR_SIZE: 152 | if (spec->size != SPEC_SIZE_NULL) 153 | decl_spec_error(spec, select); 154 | spec->size = *(spec_size_t*)value; 155 | break; 156 | case SPEC_VAR_TYPE: 157 | if (spec->type != SPEC_TYPE_NULL) 158 | decl_spec_error(spec, select); 159 | spec->type = *(spec_type_t*)value; 160 | break; 161 | case SPEC_VAR_USER: 162 | if (spec->user != 0) 163 | decl_spec_error(spec, select); 164 | spec->user = value; 165 | break; 166 | default: 167 | compile_ice("decl_spec_get state machine got null variable reference"); 168 | break; 169 | } 170 | 171 | /* bool cannot have a sign, it's only legal as it's own entity. */ 172 | if (spec->type == SPEC_TYPE_BOOL && (spec->size != SPEC_SIZE_NULL && spec->sign != SPEC_SIGN_NULL)) 173 | decl_spec_error(spec, select); 174 | 175 | switch (spec->size) { 176 | case SPEC_SIZE_SHORT: 177 | /* 178 | * short and short int are the only legal uses of the short 179 | * size specifier. 180 | */ 181 | if (spec->type != SPEC_TYPE_NULL && spec->type != SPEC_TYPE_INT) 182 | decl_spec_error(spec, select); 183 | break; 184 | 185 | case SPEC_SIZE_LONG: 186 | /* 187 | * long, long int and long double are the only legal uses of 188 | * long size specifier. 189 | */ 190 | if (spec->type != SPEC_TYPE_NULL && spec->type != SPEC_TYPE_INT && spec->type != SPEC_TYPE_DOUBLE) 191 | decl_spec_error(spec, select); 192 | break; 193 | 194 | default: 195 | break; 196 | } 197 | 198 | /* 199 | * sign and unsigned sign specifiers are not legal on void, float and 200 | * double types. 201 | */ 202 | if (spec->sign != SPEC_SIGN_NULL) { 203 | switch (spec->type) { 204 | case SPEC_TYPE_VOID: 205 | case SPEC_TYPE_FLOAT: 206 | case SPEC_TYPE_DOUBLE: 207 | decl_spec_error(spec, select); 208 | break; 209 | default: 210 | break; 211 | } 212 | } 213 | 214 | /* 215 | * user types cannot have additional levels of specification on it, 216 | * for instance 'typedef unsigned int foo; 'signed foo'. 217 | */ 218 | if (spec->user && (spec->type != SPEC_TYPE_NULL || 219 | spec->size != SPEC_SIZE_NULL || 220 | spec->sign != SPEC_SIGN_NULL)) 221 | decl_spec_error(spec, select); 222 | } 223 | 224 | #define decl_spec_seti(SPEC, SELECT, VAR) \ 225 | decl_spec_set((SPEC), (SELECT), &(int){ VAR }) 226 | 227 | static data_type_t *decl_spec_get(const decl_spec_t *spec) { 228 | bool sign = !!(spec->sign != SPEC_SIGN_UNSIGNED); 229 | 230 | switch (spec->type) { 231 | case SPEC_TYPE_VOID: 232 | return ast_data_table[AST_DATA_VOID]; 233 | case SPEC_TYPE_BOOL: 234 | return ast_type_create(TYPE_BOOL, false); 235 | case SPEC_TYPE_CHAR: 236 | return ast_type_create(TYPE_CHAR, sign); 237 | case SPEC_TYPE_FLOAT: 238 | return ast_type_create(TYPE_FLOAT, false); 239 | case SPEC_TYPE_DOUBLE: 240 | if (spec->size == SPEC_SIZE_LONG) 241 | return ast_type_create(TYPE_LDOUBLE, false); 242 | return ast_type_create(TYPE_DOUBLE, false); 243 | default: 244 | break; 245 | } 246 | 247 | switch (spec->size) { 248 | case SPEC_SIZE_SHORT: 249 | return ast_type_create(TYPE_SHORT, sign); 250 | case SPEC_SIZE_LONG: 251 | return ast_type_create(TYPE_LONG, sign); 252 | case SPEC_SIZE_LLONG: 253 | return ast_type_create(TYPE_LLONG, sign); 254 | default: 255 | /* implicit int */ 256 | return ast_type_create(TYPE_INT, sign); 257 | } 258 | compile_ice("declaration specifier"); 259 | } 260 | 261 | data_type_t *decl_spec(storage_t *const class) { 262 | decl_spec_t spec; 263 | memset(&spec, 0, sizeof(spec)); 264 | 265 | for (;;) { 266 | lexer_token_t *token = lexer_next(); 267 | if (!token) 268 | compile_error("type specification with unexpected ending"); 269 | 270 | if (token->type != LEXER_TOKEN_IDENTIFIER) { 271 | lexer_unget(token); 272 | break; 273 | } 274 | 275 | if (!strcmp(token->string, "const")) 276 | spec.kconst = true; 277 | else if (!strcmp(token->string, "volatile")) 278 | spec.kvolatile = true; 279 | else if (!strcmp(token->string, "inline")) 280 | spec.kinline = true; 281 | else if (!strcmp(token->string, "typedef")) 282 | decl_spec_class(&spec, STORAGE_TYPEDEF); 283 | else if (!strcmp(token->string, "extern")) 284 | decl_spec_class(&spec, STORAGE_EXTERN); 285 | else if (!strcmp(token->string, "static") || !strcmp(token->string, "__static__")) 286 | decl_spec_class(&spec, STORAGE_STATIC); 287 | else if (!strcmp(token->string, "auto")) 288 | decl_spec_class(&spec, STORAGE_AUTO); 289 | else if (!strcmp(token->string, "register")) 290 | decl_spec_class(&spec, STORAGE_REGISTER); 291 | else if (!strcmp(token->string, "void")) 292 | decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_VOID); 293 | else if (!strcmp(token->string, "_Bool")) 294 | decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_BOOL); 295 | else if (!strcmp(token->string, "char")) 296 | decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_CHAR); 297 | else if (!strcmp(token->string, "int")) 298 | decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_INT); 299 | else if (!strcmp(token->string, "float")) 300 | decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_FLOAT); 301 | else if (!strcmp(token->string, "double")) 302 | decl_spec_seti(&spec, SPEC_VAR_TYPE, SPEC_TYPE_DOUBLE); 303 | else if (!strcmp(token->string, "signed")) 304 | decl_spec_seti(&spec, SPEC_VAR_SIGN, SPEC_SIGN_SIGNED); 305 | else if (!strcmp(token->string, "unsigned")) 306 | decl_spec_seti(&spec, SPEC_VAR_SIGN, SPEC_SIGN_UNSIGNED); 307 | else if (!strcmp(token->string, "struct")) 308 | decl_spec_set(&spec, SPEC_VAR_USER, parse_structure()); 309 | else if (!strcmp(token->string, "union")) 310 | decl_spec_set(&spec, SPEC_VAR_USER, parse_union()); 311 | else if (!strcmp(token->string, "enum")) 312 | decl_spec_set(&spec, SPEC_VAR_USER, parse_enumeration()); 313 | else if (!strcmp(token->string, "short")) 314 | decl_spec_seti(&spec, SPEC_VAR_SIZE, SPEC_SIZE_SHORT); 315 | else if (!strcmp(token->string, "long")) { 316 | if (spec.size == 0) 317 | decl_spec_seti(&spec, SPEC_VAR_SIZE, SPEC_SIZE_LONG); 318 | else if (spec.size == SPEC_SIZE_LONG) 319 | spec.size = SPEC_SIZE_LLONG; 320 | else 321 | decl_spec_error(&spec, SPEC_VAR_NULL); 322 | } 323 | else if (!strcmp(token->string, "typeof") || !strcmp(token->string, "__typeof__")) 324 | decl_spec_set(&spec, SPEC_VAR_USER, parse_typeof()); 325 | else if (parse_typedef_find(token->string) && !spec.user) 326 | decl_spec_set(&spec, SPEC_VAR_USER, parse_typedef_find(token->string)); 327 | else { 328 | lexer_unget(token); 329 | break; 330 | } 331 | } 332 | 333 | if (class) 334 | *class = spec.class; 335 | if (spec.user) 336 | return spec.user; 337 | 338 | return decl_spec_get(&spec); 339 | } 340 | -------------------------------------------------------------------------------- /gen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File: gen.c 3 | * Common code generator facilities. 4 | */ 5 | #include 6 | #include 7 | 8 | #include "gen.h" 9 | #include "lice.h" 10 | 11 | char *gen_label_break = NULL; 12 | char *gen_label_continue = NULL; 13 | char *gen_label_switch = NULL; 14 | char *gen_label_break_backup = NULL; 15 | char *gen_label_continue_backup = NULL; 16 | char *gen_label_switch_backup = NULL; 17 | 18 | static void gen_emit_emitter(bool indent, const char *fmt, va_list list) { 19 | if (indent) 20 | fputc('\t', stdout); 21 | 22 | va_list va; 23 | va_copy(va, list); 24 | vprintf(fmt, va); 25 | va_end(va); 26 | 27 | fputc('\n', stdout); 28 | } 29 | 30 | void gen_emit(const char *fmt, ...) { 31 | va_list va; 32 | va_start(va, fmt); 33 | gen_emit_emitter(true, fmt, va); 34 | va_end(va); 35 | } 36 | 37 | void gen_emit_inline(const char *fmt, ...) { 38 | va_list va; 39 | va_start(va, fmt); 40 | gen_emit_emitter(false, fmt, va); 41 | va_end(va); 42 | } 43 | 44 | void gen_jump_backup(void) { 45 | gen_label_break_backup = gen_label_break; 46 | gen_label_continue_backup = gen_label_continue; 47 | } 48 | 49 | void gen_jump_save(char *lbreak, char *lcontinue) { 50 | gen_jump_backup(); 51 | 52 | gen_label_break = lbreak; 53 | gen_label_continue = lcontinue; 54 | } 55 | 56 | void gen_jump_restore(void) { 57 | gen_label_break = gen_label_break_backup; 58 | gen_label_continue = gen_label_continue_backup; 59 | } 60 | 61 | void gen_jump(const char *label) { 62 | if (!label) 63 | compile_ice("gen_jump"); 64 | 65 | gen_emit("jmp %s", label); 66 | } 67 | 68 | void gen_label(const char *label) { 69 | gen_emit("%s:", label); 70 | } 71 | 72 | /* 73 | * Some expressions are architecture-independent thanks to generic generation 74 | * functions. 75 | */ 76 | static void gen_statement_switch(ast_t *ast) { 77 | gen_label_switch_backup = gen_label_switch; 78 | gen_label_break_backup = gen_label_break; 79 | gen_expression(ast->switchstmt.expr); 80 | gen_label_switch = ast_label(); 81 | gen_label_break = ast_label(); 82 | gen_jump(gen_label_switch); 83 | if (ast->switchstmt.body) 84 | gen_expression(ast->switchstmt.body); 85 | gen_label(gen_label_switch); 86 | gen_label(gen_label_break); 87 | gen_label_switch = gen_label_switch_backup; 88 | gen_label_break = gen_label_break_backup; 89 | } 90 | 91 | static void gen_statement_do(ast_t *ast) { 92 | char *begin = ast_label(); 93 | char *end = ast_label(); 94 | gen_jump_save(end, begin); 95 | gen_label(begin); 96 | gen_expression(ast->forstmt.body); 97 | gen_expression(ast->forstmt.cond); 98 | gen_je(end); 99 | gen_jump(begin); 100 | gen_label(end); 101 | gen_jump_restore(); 102 | } 103 | 104 | static void gen_statement_compound(ast_t *ast) { 105 | for (list_iterator_t *it = list_iterator(ast->compound); !list_iterator_end(it); ) 106 | gen_expression(list_iterator_next(it)); 107 | } 108 | 109 | static void gen_statement_goto(ast_t *ast) { 110 | gen_jump(ast->gotostmt.where); 111 | } 112 | 113 | static void gen_statement_label(ast_t *ast) { 114 | if (ast->gotostmt.where) 115 | gen_label(ast->gotostmt.where); 116 | } 117 | 118 | static void gen_statement_cond(ast_t *ast) { 119 | gen_expression(ast->ifstmt.cond); 120 | char *ne = ast_label(); 121 | gen_je(ne); 122 | if (ast->ifstmt.then) 123 | gen_expression(ast->ifstmt.then); 124 | if (ast->ifstmt.last) { 125 | char *end = ast_label(); 126 | gen_jump(end); 127 | gen_label(ne); 128 | gen_expression(ast->ifstmt.last); 129 | gen_label(end); 130 | } else { 131 | gen_label(ne); 132 | } 133 | } 134 | 135 | static void gen_statement_for(ast_t *ast) { 136 | if (ast->forstmt.init) 137 | gen_expression(ast->forstmt.init); 138 | char *begin = ast_label(); 139 | char *step = ast_label(); 140 | char *end = ast_label(); 141 | gen_jump_save(end, step); 142 | gen_label(begin); 143 | if (ast->forstmt.cond) { 144 | gen_expression(ast->forstmt.cond); 145 | gen_je(end); 146 | } 147 | gen_expression(ast->forstmt.body); 148 | gen_label(step); 149 | if (ast->forstmt.step) 150 | gen_expression(ast->forstmt.step); 151 | gen_jump(begin); 152 | gen_label(end); 153 | gen_jump_restore(); 154 | } 155 | 156 | static void gen_statement_while(ast_t *ast) { 157 | char *begin = ast_label(); 158 | char *end = ast_label(); 159 | gen_jump_save(end, begin); 160 | gen_label(begin); 161 | gen_expression(ast->forstmt.cond); 162 | gen_je(end); 163 | gen_expression(ast->forstmt.body); 164 | gen_jump(begin); 165 | gen_label(end); 166 | gen_jump_restore(); 167 | } 168 | 169 | static void gen_statement_return(ast_t *ast) { 170 | if (ast->returnstmt) { 171 | gen_expression(ast->returnstmt); 172 | gen_boolean_maybe(ast->returnstmt->ctype); 173 | } 174 | gen_return(); 175 | } 176 | 177 | static void gen_statement_break(void) { 178 | gen_jump(gen_label_break); 179 | } 180 | 181 | static void gen_statement_continue(void) { 182 | gen_jump(gen_label_continue); 183 | } 184 | 185 | static void gen_statement_default(void) { 186 | gen_label(gen_label_switch); 187 | gen_label_switch = ast_label(); 188 | } 189 | 190 | static void gen_comma(ast_t *ast) { 191 | gen_expression(ast->left); 192 | gen_expression(ast->right); 193 | } 194 | 195 | static void gen_data_bss(ast_t *ast) { 196 | gen_emit(".data"); 197 | if (!ast->decl.var->ctype->isstatic) 198 | gen_emit(".global %s", ast->decl.var->variable.name); 199 | gen_emit(".lcomm %s, %d", ast->decl.var->variable.name, ast->decl.var->ctype->size); 200 | } 201 | 202 | static void gen_data_global(ast_t *variable) { 203 | if (variable->decl.init) 204 | gen_data(variable, 0, 0); 205 | else 206 | gen_data_bss(variable); 207 | } 208 | 209 | static void gen_declaration_initialization(list_t *init, int offset) { 210 | for (list_iterator_t *it = list_iterator(init); !list_iterator_end(it); ) { 211 | ast_t *node = list_iterator_next(it); 212 | if (node->init.value->type == AST_TYPE_LITERAL && node->init.type->bitfield.size <= 0) 213 | gen_literal_save(node->init.value, node->init.type, node->init.offset + offset); 214 | else { 215 | gen_expression(node->init.value); 216 | gen_save_local(node->init.type, node->init.offset + offset); 217 | } 218 | } 219 | } 220 | 221 | static void gen_declaration(ast_t *ast) { 222 | if (!ast->decl.init) 223 | return; 224 | 225 | gen_zero(ast->decl.var->variable.off, ast->decl.var->variable.off + ast->decl.var->ctype->size); 226 | gen_declaration_initialization(ast->decl.init, ast->decl.var->variable.off); 227 | } 228 | 229 | void gen_ensure_lva(ast_t *ast) { 230 | if (ast->variable.init) { 231 | gen_zero(ast->variable.off, ast->variable.off + ast->ctype->size); 232 | gen_declaration_initialization(ast->variable.init, ast->variable.off); 233 | } 234 | ast->variable.init = NULL; 235 | } 236 | 237 | void gen_expression(ast_t *ast) { 238 | if (!ast) return; 239 | 240 | switch (ast->type) { 241 | case AST_TYPE_STATEMENT_IF: gen_statement_cond(ast); break; 242 | case AST_TYPE_EXPRESSION_TERNARY: gen_statement_cond(ast); break; 243 | case AST_TYPE_STATEMENT_FOR: gen_statement_for(ast); break; 244 | case AST_TYPE_STATEMENT_WHILE: gen_statement_while(ast); break; 245 | case AST_TYPE_STATEMENT_DO: gen_statement_do(ast); break; 246 | case AST_TYPE_STATEMENT_COMPOUND: gen_statement_compound(ast); break; 247 | case AST_TYPE_STATEMENT_SWITCH: gen_statement_switch(ast); break; 248 | case AST_TYPE_STATEMENT_GOTO: gen_statement_goto(ast); break; 249 | case AST_TYPE_STATEMENT_LABEL: gen_statement_label(ast); break; 250 | case AST_TYPE_STATEMENT_RETURN: gen_statement_return(ast); break; 251 | case AST_TYPE_STATEMENT_BREAK: gen_statement_break(); break; 252 | case AST_TYPE_STATEMENT_CONTINUE: gen_statement_continue(); break; 253 | case AST_TYPE_STATEMENT_DEFAULT: gen_statement_default(); break; 254 | case AST_TYPE_CALL: gen_function_call(ast); break; 255 | case AST_TYPE_POINTERCALL: gen_function_call(ast); break; 256 | case AST_TYPE_LITERAL: gen_literal(ast); break; 257 | case AST_TYPE_STRING: gen_literal_string(ast); break; 258 | case AST_TYPE_VAR_LOCAL: gen_variable_local(ast); break; 259 | case AST_TYPE_VAR_GLOBAL: gen_variable_global(ast); break; 260 | case AST_TYPE_DECLARATION: gen_declaration(ast); break; 261 | case AST_TYPE_DEREFERENCE: gen_dereference(ast); break; 262 | case AST_TYPE_ADDRESS: gen_address(ast->unary.operand); break; 263 | case AST_TYPE_STATEMENT_CASE: gen_case(ast); break; 264 | case AST_TYPE_VA_START: gen_va_start(ast); break; 265 | case AST_TYPE_VA_ARG: gen_va_arg(ast); break; 266 | case '!': gen_not(ast); break; 267 | case AST_TYPE_NEGATE: gen_negate(ast); break; 268 | case AST_TYPE_AND: gen_and(ast); break; 269 | case AST_TYPE_OR: gen_or(ast); break; 270 | case AST_TYPE_POST_INCREMENT: gen_postfix(ast, "add"); break; 271 | case AST_TYPE_POST_DECREMENT: gen_postfix(ast, "sub"); break; 272 | case AST_TYPE_PRE_INCREMENT: gen_prefix (ast, "add"); break; 273 | case AST_TYPE_PRE_DECREMENT: gen_prefix (ast, "sub"); break; 274 | case AST_TYPE_EXPRESSION_CAST: gen_cast(ast); break; 275 | case AST_TYPE_STRUCT: gen_struct(ast); break; 276 | case '&': gen_bitandor(ast); break; 277 | case '|': gen_bitandor(ast); break; 278 | case '~': gen_bitnot(ast); break; 279 | case ',': gen_comma(ast); break; 280 | case '=': gen_assign(ast); break; 281 | case AST_TYPE_CONVERT: gen_conversion(ast); break; 282 | case AST_TYPE_STATEMENT_GOTO_COMPUTED: gen_goto_computed(ast); break; 283 | case AST_TYPE_STATEMENT_LABEL_COMPUTED: gen_address_label(ast); break; 284 | default: 285 | gen_binary(ast); 286 | } 287 | } 288 | 289 | void gen_toplevel(ast_t *ast) { 290 | gen_function(ast); 291 | if (ast->type == AST_TYPE_FUNCTION) { 292 | gen_function_prologue(ast); 293 | gen_expression(ast->function.body); 294 | gen_function_epilogue(); 295 | } else if (ast->type == AST_TYPE_DECLARATION) { 296 | gen_data_global(ast); 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /gen.h: -------------------------------------------------------------------------------- 1 | #ifndef LICE_GEN_HDR 2 | #define LICE_GEN_HDR 3 | #include "ast.h" 4 | 5 | extern char *gen_label_break; 6 | extern char *gen_label_continue; 7 | extern char *gen_label_switch; 8 | extern char *gen_label_break_backup; 9 | extern char *gen_label_continue_backup; 10 | extern char *gen_label_switch_backup; 11 | 12 | /* emitters */ 13 | void gen_emit(const char *fmt, ...); 14 | void gen_emit_inline(const char *fmt, ...); 15 | 16 | /* jump */ 17 | void gen_jump(const char *label); 18 | void gen_jump_backup(void); 19 | void gen_jump_save(char *lbreak, char *lcontinue); 20 | void gen_jump_restore(void); 21 | void gen_jump_break(void); 22 | void gen_jump_continue(void); 23 | 24 | /* label */ 25 | void gen_label(const char *label); 26 | void gen_label_default(void); 27 | 28 | /* expression */ 29 | void gen_expression(ast_t *ast); 30 | 31 | /* semantics */ 32 | void gen_ensure_lva(ast_t *ast); 33 | 34 | /* need to implement */ 35 | void gen_return(void); 36 | void gen_literal(ast_t *ast); 37 | void gen_literal_string(ast_t *ast); 38 | void gen_literal_save(ast_t *ast, data_type_t *, int); 39 | void gen_save_local(data_type_t *type, int offset); 40 | void gen_variable_local(ast_t *ast); 41 | void gen_variable_global(ast_t *ast); 42 | void gen_dereference(ast_t *ast); 43 | void gen_address(ast_t *ast); 44 | void gen_binary(ast_t *ast); 45 | void gen_zero(int start, int end); 46 | void gen_je(const char *label); 47 | void gen_data(ast_t *, int, int); 48 | void gen_function_call(ast_t *ast); 49 | void gen_case(ast_t *ast); 50 | void gen_va_start(ast_t *ast); 51 | void gen_va_arg(ast_t *ast); 52 | void gen_not(ast_t *ast); 53 | void gen_and(ast_t *ast); 54 | void gen_or(ast_t *ast); 55 | void gen_postfix(ast_t *, const char *); 56 | void gen_prefix(ast_t *, const char *); 57 | void gen_cast(ast_t *ast); 58 | void gen_struct(ast_t *); 59 | void gen_bitandor(ast_t *ast); 60 | void gen_bitnot(ast_t *ast); 61 | void gen_assign(ast_t *ast); 62 | void gen_function(ast_t *ast); 63 | void gen_function_prologue(ast_t *ast); 64 | void gen_function_epilogue(void); 65 | void gen_boolean_maybe(data_type_t *); 66 | void gen_negate(ast_t *ast); 67 | void gen_conversion(ast_t *ast); 68 | void gen_address_label(ast_t *ast); 69 | void gen_goto_computed(ast_t *ast); 70 | 71 | /* entry */ 72 | void gen_toplevel(ast_t *); 73 | #endif 74 | -------------------------------------------------------------------------------- /include/alignof.h: -------------------------------------------------------------------------------- 1 | #ifndef __ALIGNOF_HDR 2 | #define __ALIGNOF_HDR 3 | 4 | #define alignof _Alignof 5 | #define __alignof_is_defined 1 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /include/index.html: -------------------------------------------------------------------------------- 1 | /include/ 2 | 3 |

/include/

4 | 11 | 12 | -------------------------------------------------------------------------------- /include/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDARG_HDR 2 | #define __STDARG_HDR 3 | 4 | typedef struct { 5 | unsigned int gp_offset; 6 | unsigned int fp_offset; 7 | void *overflow_arg_area; 8 | void *reg_save_area; 9 | } va_list[1]; 10 | 11 | #define va_start(AP, LAST) __builtin_va_start(AP) 12 | #define va_arg(AP, TYPE) __builtin_va_arg(AP, TYPE) 13 | #define va_end(AP) 1 14 | #define va_copy(DEST, SRC) ((DEST)[0] = (SRC)[0]) 15 | 16 | 17 | #define __GNUC_VA_LIST 1 18 | typedef va_list __gnuc_va_list; // deal with gnuc headers 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /include/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDBOOL_HDR 2 | #define __STDBOOL_HDR 3 | 4 | #define bool _Bool 5 | #define true 1 6 | #define false 0 7 | #define __bool_true_false_are_defined 1 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDDEF_HDR 2 | #define __STDDEF_HDR 3 | 4 | #define NULL ((void*)0) 5 | 6 | typedef unsigned long size_t; 7 | typedef long ptrdiff_t; 8 | typedef char wchar_t; 9 | typedef long double max_align_t; 10 | 11 | #define offsetof(TYPE, MEMBER) ((size_t)&(((TYPE*)NULL)->MEMBER)) 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | / 2 | 3 |

/

4 | 41 | 42 | -------------------------------------------------------------------------------- /init.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file implements a small state machine for handling all the forms 3 | * of initialization C offers. It's called from the parser just like 4 | * declaration specification. It's a sub portion of the core parser, 5 | * seperated from all that logic due to the nature of initializer 6 | * complexity. 7 | */ 8 | #include "parse.h" 9 | #include "init.h" 10 | #include "lice.h" 11 | #include "lexer.h" 12 | #include "conv.h" 13 | 14 | #include 15 | #include 16 | 17 | static void init_element (list_t *, data_type_t *, int, bool); 18 | static void init_structure (list_t *, data_type_t *, int, bool); 19 | static void init_array (list_t *, data_type_t *, int, bool); 20 | static void init_list (list_t *, data_type_t *, int, bool); 21 | 22 | /* 23 | * Initializer elements need to be sorted by semantic order, instead 24 | * of lexical order since designated initializers are allowed to 25 | * overwrite existingly assigned fields lexically, but the order needs 26 | * to stay dependent on semantics. It's also generally more efficent for 27 | * initialization to stay sorted. 28 | */ 29 | static int init_sort_predicate(const void *p, const void *q) { 30 | const ast_t *const *restrict a = p; 31 | const ast_t *const *restrict b = q; 32 | 33 | return (*a)->init.offset < (*b)->init.offset ? -1 : 34 | (*a)->init.offset == (*b)->init.offset ? 0 : 1; 35 | } 36 | 37 | static void init_sort(list_t *inits) { 38 | size_t length = list_length(inits); 39 | size_t index = 0; 40 | ast_t **temp = memory_allocate(sizeof(ast_t *) * length); 41 | list_iterator_t *it = list_iterator(inits); 42 | 43 | while (!list_iterator_end(it)) 44 | temp[index++] = list_iterator_next(it); 45 | 46 | qsort(temp, length, sizeof(ast_t *), &init_sort_predicate); 47 | 48 | list_empty(inits); 49 | for (index = 0; index < length; index++) 50 | list_push(inits, temp[index]); 51 | } 52 | 53 | static bool init_earlyout(lexer_token_t *token, bool brace, bool designated) { 54 | if ((lexer_ispunct(token, '.') || lexer_ispunct(token, '[')) && !brace && !designated) { 55 | lexer_unget(token); 56 | return true; 57 | } 58 | return false; 59 | } 60 | 61 | /* 62 | * Utility routines to determine and skip to braces for initialization 63 | * involving aggregates. 64 | */ 65 | static bool init_skip_brace_maybe(void) { 66 | lexer_token_t *token = lexer_next(); 67 | if (lexer_ispunct(token, '{')) 68 | return true; 69 | lexer_unget(token); 70 | return false; 71 | } 72 | 73 | static void init_skip_comma_maybe(void) { 74 | lexer_token_t *token = lexer_next(); 75 | 76 | if (!lexer_ispunct(token, ',')) 77 | lexer_unget(token); 78 | } 79 | 80 | static void init_skip_brace(void) { 81 | for (;;) { 82 | /* 83 | * Potentially infinite look a head, got to love C's grammar for 84 | * this sort of crap. 85 | */ 86 | lexer_token_t *token = lexer_next(); 87 | if (lexer_ispunct(token, '}')) 88 | return; 89 | 90 | if (lexer_ispunct(token, '.')) { 91 | lexer_next(); 92 | parse_expect('='); 93 | } else { 94 | lexer_unget(token); 95 | } 96 | 97 | ast_t *ignore = parse_expression_assignment(); 98 | if (!ignore) 99 | return; 100 | 101 | compile_warn("excess elements in initializer"); 102 | init_skip_comma_maybe(); 103 | } 104 | } 105 | 106 | /* 107 | * Structure and array initialization routines: 108 | * deals with standard initialization via aggregate initializer, as well 109 | * as designated initialization, and nested aggreate + designation. In 110 | * the case of array designated initialization array subscripting is 111 | * handled, where as in the case of structure designated initialization 112 | * field members are indexed by .fieldname. The GCC style of designated 113 | * initializers isn't supported yet, neither is range initialization. 114 | */ 115 | static void init_structure_intermediate(list_t *init, data_type_t *type, int offset, bool designated) { 116 | bool brace = init_skip_brace_maybe(); 117 | list_iterator_t *it = list_iterator(table_keys(type->fields)); 118 | 119 | for (;;) { 120 | lexer_token_t *token = lexer_next(); 121 | if (lexer_ispunct(token, '}')) { 122 | if (!brace) 123 | lexer_unget(token); 124 | return; 125 | } 126 | 127 | char *fieldname; 128 | data_type_t *fieldtype; 129 | 130 | if (init_earlyout(token, brace, designated)) 131 | return; 132 | 133 | if (lexer_ispunct(token, '.')) { 134 | if (!(token = lexer_next()) || token->type != LEXER_TOKEN_IDENTIFIER) 135 | compile_error("invalid designated initializer"); 136 | fieldname = token->string; 137 | if (!(fieldtype = table_find(type->fields, fieldname))) 138 | compile_error("field `%s' doesn't exist in designated initializer", fieldname); 139 | 140 | it = list_iterator(table_keys(type->fields)); 141 | while (!list_iterator_end(it)) 142 | if (!strcmp(fieldname, list_iterator_next(it))) 143 | break; 144 | designated = true; 145 | } else { 146 | lexer_unget(token); 147 | if (list_iterator_end(it)) 148 | break; 149 | 150 | fieldname = list_iterator_next(it); 151 | fieldtype = table_find(type->fields, fieldname); 152 | } 153 | init_element(init, fieldtype, offset + fieldtype->offset, designated); 154 | init_skip_comma_maybe(); 155 | designated = false; 156 | 157 | if (!type->isstruct) 158 | break; 159 | } 160 | if (brace) 161 | init_skip_brace(); 162 | } 163 | 164 | static void init_array_intermediate(list_t *init, data_type_t *type, int offset, bool designated) { 165 | bool brace = init_skip_brace_maybe(); 166 | bool flexible = (type->length <= 0); 167 | int size = type->pointer->size; 168 | int i; 169 | 170 | for (i = 0; flexible || i < type->length; i++) { 171 | lexer_token_t *token = lexer_next(); 172 | if (lexer_ispunct(token, '}')) { 173 | if (!brace) 174 | lexer_unget(token); 175 | goto complete; 176 | } 177 | 178 | if (init_earlyout(token, brace, designated)) 179 | return; 180 | 181 | if (lexer_ispunct(token, '[')) { 182 | /* designated array initializer */ 183 | int index = parse_expression_evaluate(); 184 | if (index < 0 || (!flexible && type->length <= index)) 185 | compile_error("out of bounds"); 186 | i = index; 187 | parse_expect(']'); 188 | designated = true; 189 | } else { 190 | lexer_unget(token); 191 | } 192 | init_element(init, type->pointer, offset + size * i, designated); 193 | init_skip_comma_maybe(); 194 | designated = false; 195 | } 196 | if (brace) 197 | init_skip_brace(); 198 | 199 | complete: 200 | if (type->length < 0) { 201 | type->length = i; 202 | type->size = size * i; 203 | } 204 | } 205 | 206 | /* 207 | * Intermediate stages deal with all the logic, these functions are 208 | * just tail calls (hopefully optimized) to the intermediate stages followed 209 | * by a sorting of the elements to honor semantic ordering of initialization. 210 | */ 211 | static void init_structure(list_t *init, data_type_t *type, int offset, bool designated) { 212 | init_structure_intermediate(init, type, offset, designated); 213 | init_sort(init); 214 | } 215 | 216 | static void init_array(list_t *init, data_type_t *type, int offset, bool designated) { 217 | init_array_intermediate(init, type, offset, designated); 218 | init_sort(init); 219 | } 220 | 221 | /* 222 | * The entry points to the initializers, single element initialization 223 | * and initializer list initialization will dispatch into the appropriate 224 | * initialization parsing routines as defined above. 225 | */ 226 | static void init_element(list_t *init, data_type_t *type, int offset, bool designated) { 227 | parse_next('='); 228 | if (type->type == TYPE_ARRAY || type->type == TYPE_STRUCTURE) 229 | init_list(init, type, offset, designated); 230 | else if (parse_next('{')) { 231 | init_element(init, type, offset, designated); 232 | parse_expect('}'); 233 | } else { 234 | ast_t *expression = parse_expression_assignment(); 235 | parse_semantic_assignable(type, expression->ctype); 236 | list_push(init, ast_initializer(expression, type, offset)); 237 | } 238 | } 239 | 240 | static void init_string(list_t *init, data_type_t *type, char *p, int offset) { 241 | if (type->length == -1) 242 | type->length = type->size = strlen(p) + 1; 243 | 244 | int i = 0; 245 | for (; i < type->length && *p; i++) { 246 | list_push(init, ast_initializer( 247 | ast_new_integer(ast_data_table[AST_DATA_CHAR], *p++), 248 | ast_data_table[AST_DATA_CHAR], offset + i 249 | )); 250 | } 251 | for (; i < type->length; i++) { 252 | list_push(init, ast_initializer( 253 | ast_new_integer(ast_data_table[AST_DATA_CHAR], 0), 254 | ast_data_table[AST_DATA_CHAR], offset + i 255 | )); 256 | } 257 | } 258 | 259 | static void init_list(list_t *init, data_type_t *type, int offset, bool designated) { 260 | lexer_token_t *token = lexer_next(); 261 | if (ast_type_isstring(type)) { 262 | if (token->type == LEXER_TOKEN_STRING) { 263 | init_string(init, type, token->string, offset); 264 | return; 265 | } 266 | 267 | if (lexer_ispunct(token, '{') && lexer_peek()->type == LEXER_TOKEN_STRING) { 268 | token = lexer_next(); 269 | init_string(init, type, token->string, offset); 270 | parse_expect('}'); 271 | return; 272 | } 273 | } 274 | lexer_unget(token); 275 | 276 | if (type->type == TYPE_ARRAY) 277 | init_array(init, type, offset, designated); 278 | else if (type->type == TYPE_STRUCTURE) 279 | init_structure(init, type, offset, designated); 280 | else 281 | init_array(init, ast_array(type, 1), offset, designated); 282 | } 283 | 284 | /* 285 | * Actual entry point of the parser, parses an initializer list, while 286 | * also dispatching into the appropriate parser routines depending on 287 | * certain state like, array/structure, designated or not. 288 | */ 289 | list_t *init_entry(data_type_t *type) { 290 | list_t *list = list_create(); 291 | if (lexer_ispunct(lexer_peek(), '{') || ast_type_isstring(type)) { 292 | init_list(list, type, 0, false); 293 | return list; 294 | } 295 | 296 | ast_t *init = parse_expression_assignment(); 297 | if (conv_capable(init->ctype) && init->ctype->type != type->type) 298 | init = ast_type_convert(type, init); 299 | list_push(list, ast_initializer(init, type, 0)); 300 | 301 | return list; 302 | } 303 | -------------------------------------------------------------------------------- /init.h: -------------------------------------------------------------------------------- 1 | #ifndef LICE_INIT_HDR 2 | #define LICE_INIT_HDR 3 | #include "ast.h" 4 | #include "util.h" 5 | 6 | /* 7 | * Function: init_entry 8 | * The core entry point to initializer parsing. 9 | * 10 | * Parameters: 11 | * type - Base type of the current initializer 12 | * 13 | * Returns: 14 | * A list containing all the initialization nodes for the initializer 15 | * 16 | * Remarks: 17 | * Deals with all forms of initialization, lists, aggregates, including 18 | * designated versions for user defined unions, structures, arrays and 19 | * enumerations. 20 | * 21 | * Will raise compiler error if syntax or lexical error in initializer 22 | * resulting in a NULL, or partially filled list of ast initializer 23 | * nodes. 24 | */ 25 | list_t *init_entry(data_type_t *type); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /lexer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "lexer.h" 7 | #include "util.h" 8 | #include "lice.h" 9 | #include "opt.h" 10 | 11 | static list_t *lexer_buffer = &SENTINEL_LIST; 12 | 13 | typedef struct { 14 | char *file; 15 | size_t line; 16 | FILE *fp; 17 | } lexer_file_t; 18 | 19 | static int lexer_continuation = -1; 20 | static lexer_file_t lexer_file; 21 | 22 | __attribute__((constructor)) void lexer_init(void) { 23 | lexer_file.file = "(stdin)"; 24 | lexer_file.line = 1; 25 | lexer_file.fp = stdin; 26 | } 27 | 28 | static void lexer_file_unget(int ch) { 29 | if (ch == '\n') 30 | lexer_file.line --; 31 | if (lexer_continuation >= 0) 32 | ungetc(lexer_continuation, lexer_file.fp); 33 | lexer_continuation = ch; 34 | } 35 | 36 | static int lexer_file_get(void) { 37 | int ch = (lexer_continuation < 0) ? getc(lexer_file.fp) : lexer_continuation; 38 | lexer_continuation = -1; 39 | if (ch == '\\') { 40 | if ((ch = getc(lexer_file.fp)) == '\n') { 41 | lexer_file.line ++; 42 | return lexer_file_get(); 43 | } 44 | lexer_file_unget(ch); 45 | return '\\'; 46 | 47 | } 48 | if (ch == '\n') 49 | lexer_file.line ++; 50 | 51 | return ch; 52 | } 53 | 54 | static lexer_token_t *lexer_token_copy(lexer_token_t *token) { 55 | return memcpy(malloc(sizeof(lexer_token_t)), token, sizeof(lexer_token_t)); 56 | } 57 | 58 | static lexer_token_t *lexer_identifier(string_t *str) { 59 | return lexer_token_copy(&(lexer_token_t){ 60 | .type = LEXER_TOKEN_IDENTIFIER, 61 | .string = string_buffer(str) 62 | }); 63 | } 64 | static lexer_token_t *lexer_strtok(string_t *str) { 65 | return lexer_token_copy(&(lexer_token_t){ 66 | .type = LEXER_TOKEN_STRING, 67 | .string = string_buffer(str) 68 | }); 69 | } 70 | static lexer_token_t *lexer_punct(int punct) { 71 | return lexer_token_copy(&(lexer_token_t){ 72 | .type = LEXER_TOKEN_PUNCT, 73 | .punct = punct 74 | }); 75 | } 76 | static lexer_token_t *lexer_number(char *string) { 77 | return lexer_token_copy(&(lexer_token_t){ 78 | .type = LEXER_TOKEN_NUMBER, 79 | .string = string 80 | }); 81 | } 82 | static lexer_token_t *lexer_char(char value) { 83 | return lexer_token_copy(&(lexer_token_t){ 84 | .type = LEXER_TOKEN_CHAR, 85 | .character = value 86 | }); 87 | } 88 | 89 | static void lexer_skip_comment_line(void) { 90 | for (;;) { 91 | int c = lexer_file_get(); 92 | if (c == EOF) 93 | return; 94 | if (c == '\n') { 95 | lexer_file_unget(c); 96 | return; 97 | } 98 | } 99 | } 100 | 101 | static void lexer_skip_comment_block(void) { 102 | enum { 103 | comment_outside, 104 | comment_astrick 105 | } state = comment_outside; 106 | 107 | for (;;) { 108 | int c = lexer_file_get(); 109 | if (c == '*') 110 | state = comment_astrick; 111 | else if (state == comment_astrick && c == '/') 112 | return; 113 | else 114 | state = comment_outside; 115 | } 116 | } 117 | 118 | static int lexer_skip(void) { 119 | int c; 120 | while ((c = lexer_file_get()) != EOF) { 121 | if (isspace(c) || c == '\n' || c == '\r') 122 | continue; 123 | lexer_file_unget(c); 124 | return c; 125 | } 126 | return EOF; 127 | } 128 | 129 | static lexer_token_t *lexer_read_number(int c) { 130 | string_t *string = string_create(); 131 | string_cat(string, c); 132 | for (;;) { 133 | int p = lexer_file_get(); 134 | if (!isdigit(p) && !isalpha(p) && p != '.') { 135 | lexer_file_unget(p); 136 | return lexer_number(string_buffer(string)); 137 | } 138 | string_cat(string, p); 139 | } 140 | return NULL; 141 | } 142 | 143 | static bool lexer_read_character_octal_brace(int c, int *r) { 144 | if ('0' <= c && c <= '7') { 145 | *r = (*r << 3) | (c - '0'); 146 | return true; 147 | } 148 | return false; 149 | } 150 | 151 | static int lexer_read_character_octal(int c) { 152 | int r = c - '0'; 153 | if (lexer_read_character_octal_brace((c = lexer_file_get()), &r)) { 154 | if (!lexer_read_character_octal_brace((c = lexer_file_get()), &r)) 155 | lexer_file_unget(c); 156 | } else 157 | lexer_file_unget(c); 158 | return r; 159 | } 160 | 161 | static bool lexer_read_character_universal_test(unsigned int c) { 162 | if (0x800 <= c && c<= 0xDFFF) 163 | return false; 164 | return 0xA0 <= c || c == '$' || c == '@' || c == '`'; 165 | } 166 | 167 | static int lexer_read_character_universal(int length) { 168 | unsigned int r = 0; 169 | for (int i = 0; i < length; i++) { 170 | int c = lexer_file_get(); 171 | switch (c) { 172 | case '0' ... '9': r = (r << 4) | (c - '0'); continue; 173 | case 'a' ... 'f': r = (r << 4) | (c - 'a' + 10); continue; 174 | case 'A' ... 'F': r = (r << 4) | (c - 'A' + 10); continue; 175 | default: 176 | compile_error("not a valid universal character: %c", c); 177 | 178 | } 179 | } 180 | if (!lexer_read_character_universal_test(r)) { 181 | compile_error( 182 | "not a valid universal character: \\%c%0*x", 183 | (length == 4) ? 'u' : 'U', 184 | length, 185 | r 186 | ); 187 | } 188 | return r; 189 | } 190 | 191 | static int lexer_read_character_hexadecimal(void) { 192 | int c = lexer_file_get(); 193 | int r = 0; 194 | 195 | if (!isxdigit(c)) 196 | compile_error("malformatted hexadecimal character"); 197 | 198 | for (;; c = lexer_file_get()) { 199 | switch (c) { 200 | case '0' ... '9': r = (r << 4) | (c - '0'); continue; 201 | case 'a' ... 'f': r = (r << 4) | (c - 'a' + 10); continue; 202 | case 'A' ... 'F': r = (r << 4) | (c - 'A' + 10); continue; 203 | 204 | default: 205 | lexer_file_unget(c); 206 | return r; 207 | } 208 | } 209 | return -1; 210 | } 211 | 212 | static int lexer_read_character_escaped(void) { 213 | int c = lexer_file_get(); 214 | 215 | switch (c) { 216 | case '\'': return '\''; 217 | case '"': return '"'; 218 | case '?': return '?'; 219 | case '\\': return '\\'; 220 | case 'a': return '\a'; 221 | case 'b': return '\b'; 222 | case 'f': return '\f'; 223 | case 'n': return '\n'; 224 | case 'r': return '\r'; 225 | case 't': return '\t'; 226 | case 'v': return '\v'; 227 | case 'e': return '\033'; 228 | case '0' ... '7': return lexer_read_character_octal(c); 229 | case 'x': return lexer_read_character_hexadecimal(); 230 | case 'u': return lexer_read_character_universal(4); 231 | case 'U': return lexer_read_character_universal(8); 232 | case EOF: 233 | compile_error("malformatted escape sequence"); 234 | 235 | default: 236 | return c; 237 | } 238 | } 239 | 240 | static lexer_token_t *lexer_read_character(void) { 241 | int c = lexer_file_get(); 242 | int r = (c == '\\') ? lexer_read_character_escaped() : c; 243 | 244 | if (lexer_file_get() != '\'') 245 | compile_error("unterminated character"); 246 | 247 | return lexer_char((char)r); 248 | } 249 | 250 | static lexer_token_t *lexer_read_string(void) { 251 | string_t *string = string_create(); 252 | for (;;) { 253 | int c = lexer_file_get(); 254 | if (c == EOF) 255 | compile_error("Expected termination for string literal"); 256 | 257 | if (c == '"') 258 | break; 259 | if (c == '\\') 260 | c = lexer_read_character_escaped(); 261 | string_cat(string, c); 262 | } 263 | return lexer_strtok(string); 264 | } 265 | 266 | static lexer_token_t *lexer_read_identifier(int c1) { 267 | string_t *string = string_create(); 268 | string_cat(string, (char)c1); 269 | 270 | for (;;) { 271 | int c2 = lexer_file_get(); 272 | if (isalnum(c2) || c2 == '_' || c2 == '$') { 273 | string_cat(string, c2); 274 | } else { 275 | lexer_file_unget(c2); 276 | return lexer_identifier(string); 277 | } 278 | } 279 | return NULL; 280 | } 281 | 282 | static lexer_token_t *lexer_read_reclassify_one(int expect1, int a, int e) { 283 | int c = lexer_file_get(); 284 | if (c == expect1) 285 | return lexer_punct(a); 286 | lexer_file_unget(c); 287 | return lexer_punct(e); 288 | } 289 | static lexer_token_t *lexer_read_reclassify_two(int expect1, int a, int expect2, int b, int e) { 290 | int c = lexer_file_get(); 291 | if (c == expect1) 292 | return lexer_punct(a); 293 | if (c == expect2) 294 | return lexer_punct(b); 295 | lexer_file_unget(c); 296 | return lexer_punct(e); 297 | } 298 | 299 | static lexer_token_t *lexer_read_token(void); 300 | 301 | static lexer_token_t *lexer_minicpp(void) { 302 | string_t *string = string_create(); 303 | string_t *method = string_create(); 304 | char *buffer; 305 | int ch; 306 | 307 | for (const char *p = "pragma"; *p; p++) { 308 | if ((ch = lexer_file_get()) != *p) { 309 | string_cat(string, ch); 310 | goto error; 311 | } 312 | } 313 | 314 | for (ch = lexer_file_get(); ch && ch != '\n'; ch = lexer_file_get()) { 315 | if (isspace(ch)) 316 | continue; 317 | string_cat(method, ch); 318 | } 319 | 320 | buffer = string_buffer(method); 321 | 322 | if (!strcmp(buffer, "warning_disable")) 323 | compile_warning = false; 324 | if (!strcmp(buffer, "warning_enable")) 325 | compile_warning = true; 326 | 327 | goto fall; 328 | 329 | error: 330 | buffer = string_buffer(string); 331 | for (char *beg = &buffer[string_length(string)]; beg != &buffer[-1]; --beg) 332 | lexer_file_unget(*beg); 333 | 334 | fall: 335 | lexer_skip_comment_line(); 336 | return lexer_read_token(); 337 | } 338 | 339 | static lexer_token_t *lexer_read_token(void) { 340 | int c; 341 | int n; 342 | 343 | lexer_skip(); 344 | 345 | switch ((c = lexer_file_get())) { 346 | case '0' ... '9': return lexer_read_number(c); 347 | case '"': return lexer_read_string(); 348 | case '\'': return lexer_read_character(); 349 | case 'a' ... 'z': 350 | case 'A' ... 'K': 351 | case 'M' ... 'Z': 352 | case '_': 353 | return lexer_read_identifier(c); 354 | case '$': 355 | if (opt_extension_test(EXTENSION_DOLLAR)) 356 | return lexer_read_identifier(c); 357 | break; 358 | 359 | case 'L': 360 | switch ((c = lexer_file_get())) { 361 | case '"': return lexer_read_string(); 362 | case '\'': return lexer_read_character(); 363 | } 364 | lexer_file_unget(c); 365 | return lexer_read_identifier('L'); 366 | 367 | case '/': 368 | switch ((c = lexer_file_get())) { 369 | case '/': 370 | lexer_skip_comment_line(); 371 | return lexer_read_token(); 372 | case '*': 373 | lexer_skip_comment_block(); 374 | return lexer_read_token(); 375 | } 376 | if (c == '=') 377 | return lexer_punct(LEXER_TOKEN_COMPOUND_DIV); 378 | lexer_file_unget(c); 379 | return lexer_punct('/'); 380 | 381 | // ignore preprocessor lines for now 382 | case '#': 383 | return lexer_minicpp(); 384 | 385 | case '(': case ')': 386 | case ',': case ';': 387 | case '[': case ']': 388 | case '{': case '}': 389 | case '?': case ':': 390 | case '~': 391 | return lexer_punct(c); 392 | 393 | case '+': return lexer_read_reclassify_two('+', LEXER_TOKEN_INCREMENT, '=', LEXER_TOKEN_COMPOUND_ADD, '+'); 394 | case '&': return lexer_read_reclassify_two('&', LEXER_TOKEN_AND, '=', LEXER_TOKEN_COMPOUND_AND, '&'); 395 | case '|': return lexer_read_reclassify_two('|', LEXER_TOKEN_OR, '=', LEXER_TOKEN_COMPOUND_OR, '|'); 396 | case '*': return lexer_read_reclassify_one('=', LEXER_TOKEN_COMPOUND_MUL, '*'); 397 | case '%': return lexer_read_reclassify_one('=', LEXER_TOKEN_COMPOUND_MOD, '%'); 398 | case '=': return lexer_read_reclassify_one('=', LEXER_TOKEN_EQUAL, '='); 399 | case '!': return lexer_read_reclassify_one('=', LEXER_TOKEN_NEQUAL, '!'); 400 | case '^': return lexer_read_reclassify_one('=', LEXER_TOKEN_COMPOUND_XOR, '^'); 401 | 402 | case '-': 403 | switch ((c = lexer_file_get())) { 404 | case '-': return lexer_punct(LEXER_TOKEN_DECREMENT); 405 | case '>': return lexer_punct(LEXER_TOKEN_ARROW); 406 | case '=': return lexer_punct(LEXER_TOKEN_COMPOUND_SUB); 407 | default: 408 | break; 409 | } 410 | lexer_file_unget(c); 411 | return lexer_punct('-'); 412 | 413 | case '<': 414 | if ((c = lexer_file_get()) == '=') 415 | return lexer_punct(LEXER_TOKEN_LEQUAL); 416 | if (c == '<') 417 | return lexer_read_reclassify_one('=', LEXER_TOKEN_COMPOUND_LSHIFT, LEXER_TOKEN_LSHIFT); 418 | lexer_file_unget(c); 419 | return lexer_punct('<'); 420 | case '>': 421 | if ((c = lexer_file_get()) == '=') 422 | return lexer_punct(LEXER_TOKEN_GEQUAL); 423 | if (c == '>') 424 | return lexer_read_reclassify_one('=', LEXER_TOKEN_COMPOUND_RSHIFT, LEXER_TOKEN_RSHIFT); 425 | lexer_file_unget(c); 426 | return lexer_punct('>'); 427 | 428 | case '.': 429 | n = lexer_file_get(); 430 | if (isdigit(n)) { 431 | lexer_file_unget(n); 432 | return lexer_read_number(c); 433 | } 434 | if (n == '.') { 435 | string_t *str = string_create(); 436 | string_catf(str, "..%c", lexer_file_get()); 437 | return lexer_identifier(str); 438 | } 439 | lexer_file_unget(n); 440 | return lexer_punct('.'); 441 | 442 | case EOF: 443 | return NULL; 444 | 445 | default: 446 | compile_error("Unexpected character: `%c`", c); 447 | } 448 | return NULL; 449 | } 450 | 451 | bool lexer_ispunct(lexer_token_t *token, int c) { 452 | return token && (token->type == LEXER_TOKEN_PUNCT) && (token->punct == c); 453 | } 454 | 455 | void lexer_unget(lexer_token_t *token) { 456 | if (!token) 457 | return; 458 | list_push(lexer_buffer, token); 459 | } 460 | 461 | lexer_token_t *lexer_next(void) { 462 | if (list_length(lexer_buffer) > 0) 463 | return list_pop(lexer_buffer); 464 | return lexer_read_token(); 465 | } 466 | 467 | lexer_token_t *lexer_peek(void) { 468 | lexer_token_t *token = lexer_next(); 469 | lexer_unget(token); 470 | return token; 471 | } 472 | 473 | char *lexer_token_string(lexer_token_t *token) { 474 | string_t *string = string_create(); 475 | if (!token) 476 | return "(null)"; 477 | switch (token->type) { 478 | case LEXER_TOKEN_PUNCT: 479 | if (token->punct == LEXER_TOKEN_EQUAL) { 480 | string_catf(string, "=="); 481 | return string_buffer(string); 482 | } 483 | case LEXER_TOKEN_CHAR: 484 | string_cat(string, token->character); 485 | return string_buffer(string); 486 | case LEXER_TOKEN_NUMBER: 487 | string_catf(string, "%d", token->integer); 488 | return string_buffer(string); 489 | case LEXER_TOKEN_STRING: 490 | string_catf(string, "\"%s\"", token->string); 491 | return string_buffer(string); 492 | case LEXER_TOKEN_IDENTIFIER: 493 | return token->string; 494 | default: 495 | break; 496 | } 497 | compile_ice("unexpected token"); 498 | return NULL; 499 | } 500 | 501 | char *lexer_marker(void) { 502 | string_t *string = string_create(); 503 | string_catf(string, "%s:%zu", lexer_file.file, lexer_file.line); 504 | return string_buffer(string); 505 | } 506 | -------------------------------------------------------------------------------- /lexer.h: -------------------------------------------------------------------------------- 1 | #ifndef LICE_LEXER_HDR 2 | #define LICE_LEXER_HDR 3 | /* 4 | * File: lexer.h 5 | * Implements the interface for LICE's lexer 6 | */ 7 | #include 8 | 9 | /* 10 | * Type: lexer_token_type_t 11 | * Type to describe a tokens type. 12 | * 13 | * Remarks: 14 | * Implemented as a typedef of an enumeration, lexer_token_t 15 | * is used to describe the current lexer token. The following 16 | * tokens exist (as constants). 17 | * 18 | * Tokens: 19 | * LEXER_TOKEN_IDENTIFIER - Identifier 20 | * LEXER_TOKEN_PUNCT - Language punctuation 21 | * LEXER_TOKEN_CHAR - Character literal 22 | * LEXER_TOKEN_STRING - String literal 23 | * LEXER_TOKEN_NUMBER - Number (of any type) 24 | * LEXER_TOKEN_EQUAL - Equal 25 | * LEXER_TOKEN_LEQUAL - Lesser-or-equal 26 | * LEXER_TOKEN_GEQUAL - Greater-or-equal 27 | * LEXER_TOKEN_NEQUAL - Not-equal 28 | * LEXER_TOKEN_INCREMENT - Pre/post increment 29 | * LEXER_TOKEN_DECREMENT - Pre/post decrement 30 | * LEXER_TOKEN_ARROW - Pointer arrow `->` 31 | * LEXER_TOKEN_LSHIFT - Left shift 32 | * LEXER_TOKEN_RSHIFT - Right shift 33 | * LEXER_TOKEN_COMPOUND_ADD - Compound-assignment addition 34 | * LEXER_TOKEN_COMPOUND_SUB - Compound-assignment subtraction 35 | * LEXER_TOKEN_COMPOUND_MUL - Compound-assignment multiplication 36 | * LEXER_TOKEN_COMPOUND_DIV - Compound-assignment division 37 | * LEXER_TOKEN_COMPOUND_MOD - Compound-assignment moduluas 38 | * LEXER_TOKEN_COMPOUND_OR - Compound-assignment bit-or 39 | * LEXER_TOKEN_COMPOUND_XOR - Compound-assignment bit-xor 40 | * LEXER_TOKEN_COMPOUND_LSHIFT - Compound-assignment left-shift 41 | * LEXER_TOKEN_COMPOUND_RSHIFT - Compound-assignment right-shift 42 | * LEXER_TOKEN_AND - Logical and 43 | * LEXER_TOKEN_OR - Logical or 44 | */ 45 | typedef enum { 46 | LEXER_TOKEN_IDENTIFIER, 47 | LEXER_TOKEN_PUNCT, 48 | LEXER_TOKEN_CHAR, 49 | LEXER_TOKEN_STRING, 50 | LEXER_TOKEN_NUMBER, 51 | LEXER_TOKEN_EQUAL, 52 | LEXER_TOKEN_LEQUAL, 53 | LEXER_TOKEN_GEQUAL, 54 | LEXER_TOKEN_NEQUAL, 55 | LEXER_TOKEN_INCREMENT, 56 | LEXER_TOKEN_DECREMENT, 57 | LEXER_TOKEN_ARROW, 58 | LEXER_TOKEN_LSHIFT, 59 | LEXER_TOKEN_RSHIFT, 60 | LEXER_TOKEN_COMPOUND_ADD, 61 | LEXER_TOKEN_COMPOUND_SUB, 62 | LEXER_TOKEN_COMPOUND_MUL, 63 | LEXER_TOKEN_COMPOUND_DIV, 64 | LEXER_TOKEN_COMPOUND_MOD, 65 | LEXER_TOKEN_COMPOUND_AND, 66 | LEXER_TOKEN_COMPOUND_OR, 67 | LEXER_TOKEN_COMPOUND_XOR, 68 | LEXER_TOKEN_COMPOUND_LSHIFT, 69 | LEXER_TOKEN_COMPOUND_RSHIFT, 70 | LEXER_TOKEN_AND, 71 | LEXER_TOKEN_OR 72 | } lexer_token_type_t; 73 | 74 | /* 75 | * Class: lexer_token_t 76 | * Describes a token in the token stream 77 | */ 78 | typedef struct { 79 | /* 80 | * Variable: type 81 | * The token type 82 | */ 83 | lexer_token_type_t type; 84 | 85 | union { 86 | long integer; 87 | int punct; 88 | char *string; 89 | char character; 90 | }; 91 | } lexer_token_t; 92 | 93 | /* 94 | * Function: lexer_islong 95 | * Checks for a given string if it's a long-integer-literal. 96 | * 97 | * Parameters: 98 | * string - The string to check 99 | * 100 | * Remarks: 101 | * Returns `true` if the string is a long-literal, 102 | * `false` otherwise. 103 | */ 104 | bool lexer_islong(char *string); 105 | 106 | /* 107 | * Function: lexer_isint 108 | * Checks for a given string if it's a int-integer-literal. 109 | * 110 | * Parameters: 111 | * string - The string to check 112 | * 113 | * Remarks: 114 | * Returns `true` if the string is a int-literal, 115 | * `false` otherwise. 116 | */ 117 | bool lexer_isint (char *string); 118 | 119 | /* 120 | * Function: lexer_isfloat 121 | * Checks for a given string if it's a floating-point-literal. 122 | * 123 | * Parameters: 124 | * string - The string to check 125 | * 126 | * Remarks: 127 | * Returns `true` if the string is floating-point-literal, 128 | * `false` otherwise. 129 | */ 130 | bool lexer_isfloat(char *string); 131 | 132 | /* 133 | * Function: lexer_ispunct 134 | * Checks if a given token is language punctuation and matches. 135 | * 136 | * Parameters: 137 | * token - The token to test 138 | * c - The punction to test if matches 139 | * 140 | * Remarks: 141 | * Returns `true` if the given token is language punctuation and 142 | * matches *c*. 143 | */ 144 | bool lexer_ispunct(lexer_token_t *token, int c); 145 | 146 | /* 147 | * Function: lexer_unget 148 | * Undo the given token in the token stream. 149 | * 150 | * Parameters: 151 | * token - The token to unget 152 | */ 153 | void lexer_unget(lexer_token_t *token); 154 | 155 | /* 156 | * Function: lexer_next 157 | * Get the next token in the token stream. 158 | * 159 | * Returns: 160 | * The next token in the token stream or NULL 161 | * on failure or EOF. 162 | */ 163 | lexer_token_t *lexer_next(void); 164 | 165 | /* 166 | * Function: lexer_peek 167 | * Look at the next token without advancing the stream. 168 | * 169 | * Returns: 170 | * The next token without advancing the token stream or NULL on failure 171 | * or EOF. 172 | * 173 | * Remarks: 174 | * The function will peek ahead to see the next token in the stream 175 | * without advancing the lexer state. 176 | */ 177 | lexer_token_t *lexer_peek(void); 178 | 179 | /* 180 | * Function: lexer_token_string 181 | * Convert a token to a human-readable representation 182 | * 183 | * Parameters: 184 | * token - The token to convert 185 | * 186 | * Returns: 187 | * A string representation of the token or NULL on failure. 188 | */ 189 | char *lexer_token_string(lexer_token_t *token); 190 | 191 | /* 192 | * Function: lexer_marker 193 | * Get the line marker of where the lexer currently is. 194 | * 195 | * Remarks: 196 | * Currently returns file.c:line, will later be extended to also include 197 | * column marker. This is used in error reporting. 198 | */ 199 | char *lexer_marker(void); 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /lice.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "lexer.h" 8 | #include "parse.h" 9 | #include "gen.h" 10 | #include "opt.h" 11 | 12 | bool compile_warning = true; 13 | 14 | static void compile_diagnostic(const char *type, const char *fmt, va_list va) { 15 | fprintf(stderr, "%s %s: ", lexer_marker(), type); 16 | vfprintf(stderr, fmt, va); 17 | fprintf(stderr, "\n"); 18 | } 19 | 20 | void compile_error(const char *fmt, ...) { 21 | va_list a; 22 | va_start(a, fmt); 23 | compile_diagnostic("error", fmt, a); 24 | va_end(a); 25 | exit(EXIT_FAILURE); 26 | } 27 | 28 | void compile_warn(const char *fmt, ...) { 29 | if (!compile_warning) 30 | return; 31 | 32 | va_list a; 33 | va_start(a, fmt); 34 | compile_diagnostic("warning", fmt, a); 35 | va_end(a); 36 | } 37 | 38 | void compile_ice(const char *fmt, ...) { 39 | va_list a; 40 | va_start(a, fmt); 41 | compile_diagnostic("internal error", fmt, a); 42 | va_end(a); 43 | 44 | /* flush all streams */ 45 | fflush(NULL); 46 | abort(); 47 | } 48 | 49 | int compile_begin(bool dump) { 50 | parse_init(); 51 | 52 | list_t *block = parse_run(); 53 | size_t index = 0; 54 | 55 | for (list_iterator_t *it = list_iterator(block); !list_iterator_end(it); index++) { 56 | printf("# block %zu\n", index); 57 | if (!dump) { 58 | gen_toplevel(list_iterator_next(it)); 59 | } else { 60 | printf("%s", ast_string(list_iterator_next(it))); 61 | } 62 | } 63 | return true; 64 | } 65 | 66 | static bool parse_option(const char *optname, int *cargc, char ***cargv, char **out, int ds, bool split) { 67 | int argc = *cargc; 68 | char **argv = *cargv; 69 | size_t len = strlen(optname); 70 | 71 | if (strncmp(argv[0]+ds, optname, len)) 72 | return false; 73 | 74 | /* it's --optname, check how the parameter is supplied */ 75 | if (argv[0][ds+len] == '=') { 76 | *out = argv[0]+ds+len+1; 77 | return true; 78 | } 79 | 80 | if (!split || argc < ds) /* no parameter was provided, or only single-arg form accepted */ 81 | return false; 82 | 83 | /* using --opt param */ 84 | *out = argv[1]; 85 | --*cargc; 86 | ++*cargv; 87 | 88 | return true; 89 | } 90 | 91 | int main(int argc, char **argv) { 92 | bool dumpast = false; 93 | char *standard = NULL; 94 | 95 | while (argc > 1) { 96 | ++argv; 97 | --argc; 98 | 99 | if (argv[0][0] == '-') { 100 | if (parse_option("std", &argc, &argv, &standard, 1, false)) 101 | continue; 102 | } 103 | 104 | if (!strcmp(*argv, "--dump-ast")) { 105 | dumpast = true; 106 | continue; 107 | } 108 | 109 | fprintf(stderr, "unknown option: %s\n", argv[argc-1]); 110 | return EXIT_FAILURE; 111 | } 112 | 113 | if (standard) { 114 | if (!strcmp(standard, "licec")) opt_std_set(STANDARD_LICEC); 115 | else if (!strcmp(standard, "gnuc")) opt_std_set(STANDARD_GNUC); 116 | else if (!strcmp(standard, "c90")) opt_std_set(STANDARD_C90); 117 | else if (!strcmp(standard, "c99")) opt_std_set(STANDARD_C99); 118 | else if (!strcmp(standard, "c11")) opt_std_set(STANDARD_C11); 119 | else if (!strcmp(standard, "kandr")) opt_std_set(STANDARD_KANDR); 120 | else { 121 | fprintf(stderr, "unknown standard: %s\n", standard); 122 | return EXIT_FAILURE; 123 | } 124 | } 125 | 126 | return compile_begin(dumpast); 127 | } 128 | -------------------------------------------------------------------------------- /lice.h: -------------------------------------------------------------------------------- 1 | #ifndef LICE_HDR 2 | #define LICE_HDR 3 | #include "util.h" 4 | 5 | #ifdef LICE_TARGET_AMD64 6 | # include "arch_amd64.h" 7 | #else 8 | /* 9 | * Any additional future targets will just keep bracing with 10 | * conditional inclusion here. 11 | */ 12 | # include "arch_dummy.h" 13 | #endif 14 | 15 | #ifdef __GNUC__ 16 | # define NORETURN __attribute__((noreturn)) 17 | #else 18 | # define NORETURN 19 | #endif 20 | 21 | /* 22 | * Function: compile_error 23 | * Write compiler error diagnostic to stderr, formatted 24 | * 25 | * Parameters: 26 | * fmt - Standard format specification string 27 | * ... - Additional variable arguments 28 | * 29 | * Remarks: 30 | * This function does not return, it kills execution via a call to 31 | * exit(1); 32 | */ 33 | void NORETURN compile_error(const char *fmt, ...); 34 | 35 | /* 36 | * Function: compile_warn 37 | * Write compiler warning diagnostic to stderr, formatted 38 | * 39 | * Parameters: 40 | * fmt - Standard format specification string 41 | * ... - Additional variable arguments 42 | */ 43 | void compile_warn(const char *fmt, ...); 44 | 45 | /* 46 | * Function: compile_ice 47 | * Write an internal compiler error diagnostic to stderr, formatted 48 | * and abort. 49 | * 50 | * Parameters: 51 | * fmt - Standard format specification string 52 | * ... - Additional variable arguments 53 | * 54 | * Remarks: 55 | * Thie function does not return, it aborts execution via a call to 56 | * abort() 57 | */ 58 | void NORETURN compile_ice(const char *fmt, ...); 59 | 60 | /* TODO: eliminate */ 61 | extern bool compile_warning; 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /lice/.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: 3 | - gcc 4 | - clang 5 | script: make && make test 6 | notifications: 7 | irc: 8 | channels: 9 | - "irc.freenode.org#gmqcc" 10 | template: 11 | - "[%{commit} : %{author}] %{message}" 12 | - "%{build_url}" 13 | skip_join: true 14 | -------------------------------------------------------------------------------- /list.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include "list.h" 3 | 4 | typedef struct list_node_s list_node_t; 5 | 6 | struct list_node_s { 7 | void *element; 8 | list_node_t *next; 9 | list_node_t *prev; 10 | }; 11 | 12 | struct list_iterator_s { 13 | list_node_t *pointer; 14 | }; 15 | 16 | list_t *list_create(void) { 17 | list_t *list = memory_allocate(sizeof(list_t)); 18 | list->length = 0; 19 | list->head = NULL; 20 | list->tail = NULL; 21 | 22 | return list; 23 | } 24 | 25 | void *list_node_create(void *element) { 26 | list_node_t *node = memory_allocate(sizeof(list_node_t)); 27 | node->element = element; 28 | node->next = NULL; 29 | node->prev = NULL; 30 | return node; 31 | } 32 | 33 | void list_push(list_t *list, void *element) { 34 | list_node_t *node = list_node_create(element); 35 | if (!list->head) 36 | list->head = node; 37 | else { 38 | list->tail->next = node; 39 | node->prev = list->tail; 40 | } 41 | list->tail = node; 42 | list->length++; 43 | } 44 | 45 | void *list_pop(list_t *list) { 46 | if (!list->head) 47 | return NULL; 48 | void *element = list->tail->element; 49 | list->tail = list->tail->prev; 50 | if (list->tail) 51 | list->tail->next = NULL; 52 | else 53 | list->head = NULL; 54 | list->length--; 55 | return element; 56 | } 57 | 58 | void *list_shift(list_t *list) { 59 | if (!list->head) 60 | return NULL; 61 | void *element = list->head->element; 62 | list->head = list->head->next; 63 | if (list->head) 64 | list->head->prev = NULL; 65 | else 66 | list->tail = NULL; 67 | list->length--; 68 | return element; 69 | } 70 | 71 | int list_length(list_t *list) { 72 | return list->length; 73 | } 74 | 75 | list_iterator_t *list_iterator(list_t *list) { 76 | list_iterator_t *iter = memory_allocate(sizeof(list_iterator_t)); 77 | iter->pointer = list->head; 78 | return iter; 79 | } 80 | 81 | void *list_iterator_next(list_iterator_t *iter) { 82 | void *ret; 83 | 84 | if (!iter->pointer) 85 | return NULL; 86 | 87 | ret = iter->pointer->element; 88 | iter->pointer = iter->pointer->next; 89 | 90 | return ret; 91 | } 92 | 93 | bool list_iterator_end(list_iterator_t *iter) { 94 | return !iter->pointer; 95 | } 96 | 97 | static void list_shiftify(list_t *list, void *element) { 98 | list_node_t *node = list_node_create(element); 99 | node->next = list->head; 100 | if (list->head) 101 | list->head->prev = node; 102 | list->head = node; 103 | if (!list->tail) 104 | list->tail = node; 105 | list->length++; 106 | } 107 | 108 | list_t *list_reverse(list_t *list) { 109 | list_t *ret = list_create(); 110 | for (list_iterator_t *it = list_iterator(list); !list_iterator_end(it); ) 111 | list_shiftify(ret, list_iterator_next(it)); 112 | return ret; 113 | } 114 | 115 | void *list_tail(list_t *list) { 116 | if (!list->head) 117 | return NULL; 118 | 119 | list_node_t *node = list->head; 120 | while (node->next) 121 | node = node->next; 122 | 123 | return node->element; 124 | } 125 | 126 | void *list_head(list_t *list) { 127 | return list->head->element; 128 | } 129 | 130 | void list_empty(list_t *list) { 131 | list->length = 0; 132 | list->head = NULL; 133 | list->tail = NULL; 134 | } 135 | 136 | list_t *list_default(void *item) { 137 | list_t *list = list_create(); 138 | list_push(list, item); 139 | return list; 140 | } 141 | -------------------------------------------------------------------------------- /list.h: -------------------------------------------------------------------------------- 1 | #ifndef LICE_UTIL_LIST_HDR 2 | #define LICE_UTIL_LIST_HDR 3 | #include 4 | 5 | /* 6 | * Macro: SENTINEL_LIST 7 | * Initialize an empty list in place 8 | */ 9 | #define SENTINEL_LIST ((list_t) { \ 10 | .length = 0, \ 11 | .head = NULL, \ 12 | .tail = NULL \ 13 | }) 14 | 15 | /* 16 | * Type: list_iterator_t 17 | * A type capable of representing an itrator for a 18 | */ 19 | typedef struct list_iterator_s list_iterator_t; 20 | 21 | /* 22 | * Type: list_t 23 | * A standard double-linked list 24 | */ 25 | typedef struct list_s list_t; 26 | 27 | /* 28 | * Function: list_create 29 | * Creates a new list 30 | */ 31 | list_t *list_create(void); 32 | 33 | /* 34 | * Function: list_push 35 | * Push an element onto a list 36 | */ 37 | void list_push(list_t *list, void *element); 38 | 39 | /* 40 | * Function: list_pop 41 | * Pop an element from a list 42 | */ 43 | void *list_pop(list_t *list); 44 | 45 | /* 46 | * Function: list_length 47 | * Used to retrieve length of a list object 48 | */ 49 | int list_length(list_t *list); 50 | 51 | /* 52 | * Function: list_shift 53 | * Like a list_pop but shift from the head (instead of the tail) 54 | */ 55 | void *list_shift(list_t *list); 56 | 57 | /* 58 | * Function: list_reverse 59 | * Reverse the contents of a list 60 | */ 61 | list_t *list_reverse(list_t *list); 62 | 63 | /* 64 | * Function: list_iterator 65 | * Create an iterator for a given list object 66 | */ 67 | list_iterator_t *list_iterator(list_t *list); 68 | 69 | /* 70 | * Function: list_iterator_next 71 | * Increment the list iterator while returning the given element 72 | */ 73 | void *list_iterator_next(list_iterator_t *iter); 74 | 75 | /* 76 | * Function: list_iterator_end 77 | * Test if the iterator is at the end of the list 78 | */ 79 | bool list_iterator_end(list_iterator_t *iter); 80 | 81 | /* 82 | * Function: list_tail 83 | * Get the last element in a list 84 | * 85 | * Parameters: 86 | * list - The list in question to get the last element of. 87 | * 88 | * Returns: 89 | * The last element in the list. 90 | */ 91 | void *list_tail(list_t *list); 92 | 93 | /* 94 | * Function: list_head 95 | * Get the first element in a list 96 | * 97 | * Parameters: 98 | * list - The list in question to get the first element of. 99 | * 100 | * Returns: 101 | * The first element in the list. 102 | */ 103 | void *list_head(list_t *list); 104 | 105 | /* 106 | * Function: list_empty 107 | * Empty the contents of a list 108 | * 109 | * Parameters: 110 | * list - The list to empty the contents of. 111 | */ 112 | void list_empty(list_t *list); 113 | 114 | /* 115 | * Function: list_default 116 | * Create a new list default initializing the first element with 117 | * an item. 118 | * 119 | * Parameters: 120 | * item - The first item to default initialize the list with. 121 | * 122 | * Returns: 123 | * A new list containing one element holding `item`. 124 | */ 125 | list_t *list_default(void *item); 126 | 127 | struct list_s { 128 | int length; 129 | struct list_node_s *head; 130 | struct list_node_s *tail; 131 | }; 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /misc/argsgen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "../util.h" 6 | #define EMAX 128 // maximum arguments 7 | #define SPLIT_CALL 8 // argument count to split by newline on function calls 8 | #define SPLIT_ARG 4 // argument count to split by newline in function decls 9 | 10 | int main() { 11 | FILE *fp = fopen("tests/args.c", "w"); 12 | fprintf(fp, "// function arguments\n\n"); 13 | 14 | const char *types[] = { 15 | "int", "short", "long", 16 | "$" 17 | }; 18 | 19 | table_t *table = table_create(NULL); // table for last thing 20 | 21 | for (int e = 0; e < sizeof(types)/sizeof(types[0]); e++) { 22 | if (types[e][0] != '$') 23 | fprintf(fp, "void test_%s(", types[e]); 24 | else 25 | fprintf(fp, "void test_mix("); 26 | 27 | for (int i = 1; i < EMAX; i++) { 28 | if (types[e][0] != '$') 29 | fprintf(fp, "%-6s value%-3d", types[e], i); 30 | else { 31 | string_t *string = string_create(); 32 | const char *type = types[rand() % (sizeof(types)/sizeof(types[0]) - 1)]; 33 | fprintf(fp, "%-6s value%-3d", type, i); 34 | string_catf(string, "%d", i); 35 | table_insert(table, string_buffer(string), (void*)type); 36 | } 37 | if (i != EMAX-1) 38 | fprintf(fp, ", "); 39 | if (i % SPLIT_ARG == 0) { 40 | fprintf(fp, "\n"); 41 | if (types[e][0] != '$') { 42 | fprintf(fp, " "); // void test_ whitespace 43 | for (int j = 0; j < strlen(types[e]); j++) 44 | fprintf(fp, " "); 45 | } else { 46 | fprintf(fp, " "); 47 | } 48 | } 49 | } 50 | 51 | fprintf(fp, ") {\n"); 52 | for (int i = 1; i < EMAX; i++) { 53 | char t = types[e][0]; 54 | if (t == '$') { 55 | string_t *key = string_create(); 56 | string_catf(key, "%d", i); 57 | const char *type = table_find(table, string_buffer(key)); 58 | t = type[0]; 59 | } 60 | if (types[e][0] == 'd') 61 | fprintf(fp, " expect%c(value%d, 0.%d);\n", t, i, i); 62 | else if (types[e][0] == 'f') 63 | fprintf(fp, " expect%c(value%d, 0.%d);\n", t, i, i); 64 | else 65 | fprintf(fp, " expect%c(value%d, %d);\n", t, i, i); 66 | } 67 | fprintf(fp, "}\n"); 68 | } 69 | 70 | fprintf(fp, "int main() {\n"); 71 | for (int i = 0; i < sizeof(types)/sizeof(types[0]) - 1; i++) { 72 | fprintf(fp, " test_%s(", types[i]); 73 | for (int j = 1; j < EMAX; j++) { 74 | if (types[i][0] == 'f') { 75 | string_t *len = string_create(); 76 | string_catf(len, "0.%df", j); 77 | fprintf(fp, string_buffer(len), j); 78 | for (int p = strlen(string_buffer(len)); p <= 5; p++) 79 | fprintf(fp, " "); 80 | } else if (types[i][0] == 'd') 81 | fprintf(fp, "0.%-3d", j); 82 | else 83 | fprintf(fp, "%-3d", j); 84 | 85 | if (i != EMAX-1) 86 | fprintf(fp, ", "); 87 | 88 | if (j % SPLIT_CALL == 0) { 89 | fprintf(fp, "\n "); 90 | fprintf(fp, " "); // test_ 91 | for (int k = 0; k < strlen(types[i]); k++) 92 | fprintf(fp, " "); 93 | } 94 | } 95 | fprintf(fp, "\n );\n"); 96 | } 97 | // mix is special since it needs to align everything 98 | // at 0.ffff <-- six things 99 | fprintf(fp, " test_mix("); 100 | for (int j = 1; j < EMAX; j++) { 101 | string_t *key = string_create(); 102 | string_catf(key, "%d", j); 103 | const char *type = table_find(table, string_buffer(key)); 104 | 105 | if (type[0] == 'f') { 106 | string_t *len = string_create(); 107 | string_catf(len, "0.%df", j); 108 | fprintf(fp, string_buffer(len), j); 109 | for (int p = strlen(string_buffer(len)); p <= 5; p++) 110 | fprintf(fp, " "); 111 | } else if (type[0] == 'd') 112 | fprintf(fp, "0.%-4d", j); 113 | else 114 | fprintf(fp, "%-6d", j); 115 | 116 | if (j != EMAX-1) 117 | fprintf(fp, ", "); 118 | 119 | if (j % SPLIT_CALL == 0) { 120 | fprintf(fp, "\n "); 121 | fprintf(fp, " "); // test_mix 122 | } 123 | } 124 | fprintf(fp, "\n );\n"); 125 | fprintf(fp, " return 0;\n}\n"); 126 | fclose(fp); 127 | } 128 | -------------------------------------------------------------------------------- /misc/index.html: -------------------------------------------------------------------------------- 1 | /misc/ 2 | 3 |

/misc/

4 | 8 | 9 | -------------------------------------------------------------------------------- /opt.c: -------------------------------------------------------------------------------- 1 | #include "opt.h" 2 | 3 | static const opt_extension_t opt_extension_matrix[] = { 4 | /* 5 | * same as GNUC but no dollar identifiers, they don't make much sense 6 | * and in C11 mode, opposed to GNUC which is C99 7 | */ 8 | [STANDARD_LICEC] = EXTENSION_TYPEOF | EXTENSION_OMITOPCOND | 9 | EXTENSION_STATEMENTEXPRS | EXTENSION_NOMEMBERSTRUCT | 10 | EXTENSION_CASERANGES | EXTENSION_ESCCHAR | 11 | EXTENSION_INCOMPLETEENUM | EXTENSION_BINARYCONSTANTS | 12 | EXTENSION_ARITHMETICVOID | EXTENSION_LABELASVALUES | 13 | EXTENSION_ZEROARRAYS | EXTENSION_ZEROARRAYS | 14 | EXTENSION_NONCONSTINIT | EXTENSION_NONSTANDARD, 15 | 16 | /* 17 | * standard GNUC format, TODO: -std=gnuc90, which is the same as this 18 | * but C90, instead of C90 19 | */ 20 | [STANDARD_GNUC] = EXTENSION_TYPEOF | EXTENSION_OMITOPCOND | 21 | EXTENSION_STATEMENTEXPRS | EXTENSION_NOMEMBERSTRUCT | 22 | EXTENSION_CASERANGES | EXTENSION_ESCCHAR | 23 | EXTENSION_INCOMPLETEENUM | EXTENSION_BINARYCONSTANTS | 24 | EXTENSION_ARITHMETICVOID | EXTENSION_LABELASVALUES | 25 | EXTENSION_ZEROARRAYS | EXTENSION_ZEROARRAYS | 26 | EXTENSION_NONCONSTINIT | EXTENSION_DOLLAR | 27 | EXTENSION_NONSTANDARD, 28 | 29 | [STANDARD_C90] = 0, 30 | [STANDARD_C99] = 0, 31 | [STANDARD_C11] = 0 32 | }; 33 | 34 | static opt_std_t standard = STANDARD_LICEC; 35 | static opt_extension_t extensions = ~0; 36 | 37 | bool opt_std_test(opt_std_t std) { 38 | return (standard == std); 39 | } 40 | 41 | bool opt_extension_test(opt_extension_t ext) { 42 | return (extensions & ext); 43 | } 44 | 45 | void opt_std_set(opt_std_t std) { 46 | standard = std; 47 | extensions = opt_extension_matrix[std]; 48 | } 49 | 50 | void opt_extension_set(opt_extension_t ext) { 51 | if (opt_extension_matrix[standard] & ext) 52 | extensions &= ext; 53 | } 54 | -------------------------------------------------------------------------------- /opt.h: -------------------------------------------------------------------------------- 1 | #ifndef LICE_OPT_HDR 2 | #define LICE_OPT_HDR 3 | 4 | #include 5 | 6 | typedef enum { 7 | STANDARD_LICEC, /* LICE variant (C11 with extensions) */ 8 | STANDARD_GNUC, /* GNUC variant */ 9 | STANDARD_KANDR, /* K&R C */ 10 | STANDARD_C90, /* C90 (ISO/IEC 9899:1990) */ 11 | STANDARD_C99, /* C99 (ISO/IEC 9899:1999) */ 12 | STANDARD_C11 /* C11 (ISO/IEC 9889:2011) */ 13 | } opt_std_t; 14 | 15 | typedef enum { 16 | EXTENSION_DOLLAR = 1 << 1, /* Dollar signs in Identifier Names */ 17 | EXTENSION_TYPEOF = 1 << 2, /* Referring to a Type with typeof */ 18 | EXTENSION_OMITOPCOND = 1 << 3, /* Conditionals with Omitted Operands */ 19 | EXTENSION_STATEMENTEXPRS = 1 << 4, /* Statements and Declarations in Expressions */ 20 | EXTENSION_NOMEMBERSTRUCT = 1 << 5, /* Structures with No Members */ 21 | EXTENSION_NONCONSTINIT = 1 << 6, /* Non-Constant Initializers */ 22 | EXTENSION_CASERANGES = 1 << 7, /* Case Ranges */ 23 | EXTENSION_ESCCHAR = 1 << 8, /* The Character in Constants */ 24 | EXTENSION_INCOMPLETEENUM = 1 << 9, /* Incomplete enum Types */ 25 | EXTENSION_BINARYCONSTANTS = 1 << 10, /* Binary constants using the '0b' prefix */ 26 | EXTENSION_ARITHMETICVOID = 1 << 11, /* Arithmetic on void- and Function-Pointers */ 27 | EXTENSION_LABELASVALUES = 1 << 12, /* Labels as Values */ 28 | EXTENSION_ZEROARRAYS = 1 << 13, /* Arrays of Length Zero */ 29 | 30 | /* always the last in the list */ 31 | EXTENSION_NONSTANDARD = 1 << 14 32 | } opt_extension_t; 33 | 34 | bool opt_std_test(opt_std_t std); 35 | bool opt_extension_test(opt_extension_t ext); 36 | void opt_std_set(opt_std_t std); 37 | void opt_extension_set(opt_extension_t ext); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /parse.h: -------------------------------------------------------------------------------- 1 | #ifndef LICE_PARSE_HDR 2 | #define LICE_PARSE_HDR 3 | #include "ast.h" 4 | 5 | /* 6 | * Function: parse_enumeration 7 | * Parse an enumeration 8 | * 9 | * Returns: 10 | * A data type containing that enumeration definition 11 | */ 12 | data_type_t *parse_enumeration(void); 13 | 14 | /* 15 | * Function: parse_union 16 | * Parse a union 17 | * 18 | * Returns: 19 | * A data type containing that union definition 20 | */ 21 | data_type_t *parse_union(void); 22 | 23 | /* 24 | * Function: parse_structure 25 | * Parse a structure 26 | * 27 | * Returns: 28 | * A data type containing that structure definition 29 | */ 30 | data_type_t *parse_structure(void); 31 | 32 | /* 33 | * Fucntion: parse_typeof 34 | * Parse typeof operator 35 | * 36 | * Returns: 37 | * The data type that represents the type of the expression supplied 38 | * as the operand to the typeof operator. 39 | */ 40 | data_type_t *parse_typeof(void); 41 | 42 | /* 43 | * Function: parse_typedef_find 44 | * Search the parser typedef table for a typedef 45 | * 46 | * Parameters: 47 | * string - The key of the type to search in the typedef table 48 | * 49 | * Returns: 50 | * The data type representing that typedef if found, otherwise NULL. 51 | */ 52 | data_type_t *parse_typedef_find(const char *string); 53 | 54 | /* 55 | * Function: parse_run 56 | * Main entry point for the parser. 57 | * 58 | * Returns: 59 | * Will produce a list of AST toplevel expressions which can be handed 60 | * down to the code generator one at a time. 61 | */ 62 | list_t *parse_run(void); 63 | 64 | /* 65 | * Function: parse_init 66 | * Main initialization for the global parser context. 67 | * 68 | * Remarks: 69 | * This must be called before calling . 70 | */ 71 | void parse_init(void); 72 | 73 | /* 74 | * Function: parse_expect 75 | * When expecting language punctuation, this function is assumed to 76 | * ensure that the following lexer state does indeed contain that 77 | * punctuator. 78 | * 79 | * Parameters: 80 | * punct - A character literal of the punctuation. 81 | * 82 | * Remarks: 83 | * If the passed punctuator isn't resolved as the current lexer state 84 | * a lexer error is raised. 85 | */ 86 | void parse_expect(char punct); 87 | 88 | /* 89 | * Function: parse_next 90 | * Reads the next token in the token stream and determines if it's 91 | * the token specified by the argument, ungetting the token if it is, 92 | * ignoring it if it isn't. 93 | * 94 | * Parameters: 95 | * ch - The token to check 96 | * 97 | * Returns: 98 | * true if the token passed matches the next token in the token stream, 99 | * false otherwise. 100 | * 101 | * Remarks: 102 | * This will advance lexer state only if the token specified as a 103 | * parameter isn't determined as the next token in the token stream. 104 | */ 105 | bool parse_next(int ch); 106 | 107 | /* 108 | * Function: parse_expression_evaluate 109 | * Reads a conditional expression and evaluates it as an integer constant 110 | * expression if it one. 111 | * 112 | * Returns: 113 | * An integer constant value of the evaluation of the integer constant 114 | * expression. 115 | * 116 | * Remarks: 117 | * Will raise a compilation error if it isn't a valid integer constant 118 | * expression. 119 | */ 120 | int parse_expression_evaluate(void); 121 | 122 | /* TODO: remove */ 123 | void parse_semantic_assignable(data_type_t *to, data_type_t *from); 124 | ast_t *parse_expression_assignment(void); 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "util.h" 10 | 11 | #define TEST_DIR "tests" 12 | #define TEST_AS "gcc -xassembler" 13 | #define TEST_CPP "cpp -nostdinc -Iinclude/" 14 | #define TEST_CC "./lice -std=licec" 15 | 16 | list_t *test_find(void) { 17 | list_t *list = list_create(); 18 | DIR *dir; 19 | struct dirent *ent; 20 | 21 | if (!(dir = opendir(TEST_DIR))) 22 | return NULL; 23 | 24 | string_t *string; 25 | string_t *name; 26 | while ((ent = readdir(dir))) { 27 | if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) 28 | continue; 29 | string = string_create(); 30 | name = string_create(); 31 | 32 | string_catf(string, TEST_DIR "/%s", ent->d_name); 33 | 34 | // open file and read comment 35 | FILE *fp = fopen(string_buffer(string), "r"); 36 | char *line = NULL; 37 | size_t len = 0; 38 | getline(&line, &len, fp); 39 | fclose(fp); 40 | 41 | if (line[0] != '/' || line[1] != '/') { 42 | fprintf(stderr, "unnamed test: %s\n", string_buffer(string)); 43 | fprintf(stderr, "please give it a name, aborting"); 44 | exit(1); 45 | } 46 | 47 | // ignore whitespace 48 | char *skip = &line[2]; 49 | while (isspace(*skip)) 50 | skip++; 51 | 52 | // remove newline 53 | *strchr(skip, '\n')='\0'; 54 | 55 | string_catf(name, skip); 56 | free(line); 57 | 58 | list_push(list, pair_create(string, name)); 59 | } 60 | 61 | closedir(dir); 62 | return list; 63 | } 64 | 65 | int test_compile(string_t *file, bool ld) { 66 | string_t *command = string_create(); 67 | FILE *find; 68 | 69 | if (!(find = fopen("lice", "r"))) { 70 | fprintf(stderr, "lice not found"); 71 | exit(1); 72 | } 73 | fclose(find); 74 | 75 | string_catf(command, "{ cat testrun.c; %s %s; } | %s | %s - ", TEST_CPP, string_buffer(file), TEST_CC, TEST_AS); 76 | if (ld) 77 | string_catf(command, " -ldl"); 78 | string_catf(command, " && ./a.out"); 79 | 80 | return system(string_buffer(command)); 81 | } 82 | 83 | int main() { 84 | int error = 0; 85 | list_t *list = test_find(); 86 | 87 | 88 | bool needld = false; 89 | struct utsname u; 90 | if (uname(&u) == -1) { 91 | fprintf(stderr, "uname call failed, aborting tests"); 92 | return EXIT_FAILURE; 93 | } 94 | 95 | if (!strcmp(u.sysname, "Linux")) 96 | needld = true; 97 | 98 | 99 | if (!list) { 100 | fprintf(stderr, "%s/ %s\n", TEST_DIR, strerror(errno)); 101 | return EXIT_FAILURE; 102 | } 103 | 104 | for (list_iterator_t *it = list_iterator(list); !list_iterator_end(it); ) { 105 | pair_t *test = list_iterator_next(it); 106 | string_t *name = test->second; 107 | size_t size = string_length(name); 108 | 109 | printf("testing %s ...", string_buffer(name)); 110 | for (size_t i = 0; i < 40 - size; i++) 111 | printf(" "); 112 | 113 | if (test_compile(test->first, needld)) { 114 | printf("\033[31mERROR\033[0m\n"); 115 | error++; 116 | } else { 117 | printf("\033[32mOK\033[0m\n"); 118 | } 119 | } 120 | 121 | // print the command used for the tests 122 | printf("\nAll test were run with the following command:\n"); 123 | if (!needld) 124 | printf("{ cat testrun.c; %s $SRC; } | %s | %s - && ./a.out\n", TEST_CPP, TEST_CC, TEST_AS); 125 | else 126 | printf("{ cat testrun.c; %s $SRC; } | %s | %s - -ldl && ./a.out\n", TEST_CPP, TEST_CC, TEST_AS); 127 | 128 | return (error) ? EXIT_FAILURE 129 | : EXIT_SUCCESS; 130 | } 131 | -------------------------------------------------------------------------------- /testrun.c: -------------------------------------------------------------------------------- 1 | 2 | // some decls to suppress some warnings the compiler will emit 3 | void exit(int); 4 | int printf(const char *__format, ...); 5 | int strcmp(const char *__s1, const char *__s2); 6 | int vsprintf(char *__src, const char *__format, void *); 7 | void *dlsym(void *__handle, const char *__symbol); 8 | void *dlopen(const char *__library, long __flags); 9 | int snprintf(char *__s, unsigned long __maxlen, const char *__format); 10 | 11 | int external_1 = 1337; 12 | int external_2 = 7331; 13 | 14 | void expecti(int a, int b) { 15 | if (a != b) { 16 | printf(" Expected: %d\n", b); 17 | printf(" Result: %d\n", a); 18 | exit(1); 19 | } 20 | } 21 | 22 | void expectl(long a, long b) { 23 | if (a != b) { 24 | printf(" Expected: %d\n", b); 25 | printf(" Result: %d\n", a); 26 | exit(1); 27 | } 28 | } 29 | 30 | void expectf(float a, float b) { 31 | if (a != b) { 32 | printf(" Expected: %f\n", b); 33 | printf(" Result: %f\n", a); 34 | exit(1); 35 | } 36 | } 37 | 38 | void expectd(double a, double b) { 39 | if (a != b) { 40 | printf(" Expected: %f\n", b); 41 | printf(" Result: %f\n", a); 42 | exit(1); 43 | } 44 | } 45 | 46 | void expects(short a, short b) { 47 | if (a != b) { 48 | printf(" Expected: %s\n", b); 49 | printf(" Result: %s\n", a); 50 | exit(1); 51 | } 52 | } 53 | 54 | void expectstr(const char *a, const char *b) { 55 | if (strcmp(a, b)) { 56 | printf(" Expected: %s\n", b); 57 | printf(" Result: %s\n", a); 58 | exit(1); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tests/_Bool.c: -------------------------------------------------------------------------------- 1 | // bool 2 | 3 | #include 4 | 5 | int main(void) { 6 | expecti(__bool_true_false_are_defined, 1); 7 | 8 | _Bool a = 0; 9 | _Bool b = 1; 10 | _Bool c = 2; 11 | _Bool d = 3; 12 | 13 | expecti(a, 0); 14 | expecti(b, 1); 15 | expecti(c, 1); 16 | expecti(d, 1); 17 | 18 | a = 3; 19 | b = 2; 20 | c = 1; 21 | d = 0; 22 | 23 | expecti(a, 1); 24 | expecti(b, 1); 25 | expecti(c, 1); 26 | expecti(d, 0); 27 | 28 | bool a1 = false; 29 | a1 = !a1; 30 | a1 = (a1) ? true : false; 31 | expecti(a1, true); 32 | } 33 | -------------------------------------------------------------------------------- /tests/alignof.c: -------------------------------------------------------------------------------- 1 | // alignof 2 | 3 | #include 4 | 5 | int main(void) { 6 | expecti(__alignof_is_defined, 1); 7 | 8 | expecti(alignof(char), 1); 9 | expecti(alignof(int), 4); 10 | expecti(alignof(long), 8); 11 | 12 | struct test { 13 | char a; 14 | int b; 15 | }; 16 | 17 | expecti(alignof(struct test), 8); 18 | 19 | expecti(_Alignof(char), 1); 20 | expecti(__alignof__(char), 1); 21 | expecti(_Alignof(struct test), 8); 22 | expecti(__alignof__(struct test), 8); 23 | 24 | struct complex { 25 | struct { 26 | char a; 27 | short b; 28 | int c; 29 | } d; 30 | char e; 31 | union { 32 | int f; 33 | struct { 34 | int g; 35 | int h; 36 | } i; 37 | } j; 38 | }; 39 | 40 | expecti(alignof(struct complex), 16); 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /tests/arithmetic.c: -------------------------------------------------------------------------------- 1 | // arithmetic 2 | 3 | int main(void) { 4 | int i = 0 - 1; 5 | 6 | expecti(0, 0); 7 | expecti(1, 1); 8 | 9 | expecti(1 + 2, 3); 10 | expecti(2 - 1, 1); 11 | 12 | expecti(1 + 2 + 3 + 4, 10); 13 | expecti(1 + 2 * 3 + 4, 11); 14 | expecti(1 * 2 + 3 * 4, 14); 15 | 16 | expecti(4 / 2 + 6 / 3, 4); 17 | expecti(24 / 2 / 3 , 4); 18 | 19 | expecti(24 % 7, 3); 20 | expecti(24 % 3, 0); 21 | 22 | expecti('a' + 1, 98); 23 | expecti('b' + 1, 99); 24 | expecti('a' + 2, 'b' + 1); 25 | expecti('b' + 1, 'c'); 26 | 27 | expecti(i, 0 - 1); 28 | expecti(i, -1); 29 | expecti(i+1, 0); 30 | 31 | expecti(1, +1); 32 | 33 | i = 16; 34 | expecti(i++, 16); 35 | expecti(i, 17); 36 | expecti(i--, 17); 37 | expecti(i, 16); 38 | expecti(++i, 17); 39 | expecti(i, 17); 40 | expecti(--i, 16); 41 | expecti(i, 16); 42 | 43 | expecti(!1, 0); 44 | expecti(!0, 1); 45 | 46 | expecti((1 + 2) ? 128 : 256, 128); 47 | expecti((1 - 1) ? 128 : 256, 256); 48 | expecti((1 - 1) ? 64 : 256/2, 128); 49 | expecti((1 - 0) ? 256 : 64/2, 256); 50 | 51 | 52 | expecti((1 + 2) ?: 1024, 3); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /tests/array.c: -------------------------------------------------------------------------------- 1 | // arrays 2 | 3 | void pass(int x[][3], int want) { 4 | expecti(*(*(x + 1) + 1), want); 5 | } 6 | 7 | int main(void) { 8 | int a[2][2]; 9 | int *b = a; 10 | 11 | *b = 1024; 12 | expecti(*b, 1024); 13 | 14 | int d[2][3]; 15 | int *e = d + 1; 16 | *e = 1; 17 | int *f = d; 18 | *e = 64; 19 | expecti(*(f + 3), 64); 20 | 21 | int g[4][5]; 22 | int *h = g; 23 | *(*(g + 1) + 2) = 1024; 24 | expecti(*(h + 7), 1024); 25 | 26 | int i[] = { 1, 2, 3 }; 27 | expecti(i[0], 1); 28 | expecti(i[1], 2); 29 | expecti(i[2], 3); 30 | 31 | int j[2][3]; 32 | j[0][1] = 100; 33 | j[1][1] = 200; 34 | int *k = j; 35 | expecti(k[1], 100); 36 | expecti(k[4], 200); 37 | 38 | int l[2][3]; 39 | int *m = l; 40 | *(m + 4) = 4096; 41 | pass(l, 4096); 42 | 43 | int n[5*5]; 44 | n[10] = 25; 45 | expecti(n[10], 25); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /tests/bitwise.c: -------------------------------------------------------------------------------- 1 | // bitwise operators 2 | 3 | int main(void) { 4 | expecti(1 | 2, 3); 5 | expecti(2 | 5, 7); 6 | expecti(2 | 7, 7); 7 | 8 | expecti(1 & 2, 0); 9 | expecti(2 & 7, 2); 10 | 11 | expecti(~0, -1); 12 | expecti(~2, -3); 13 | expecti(~-1, 0); 14 | 15 | expecti(15 ^ 5, 10); 16 | 17 | expecti(1 << 4, 16); 18 | expecti(3 << 4, 48); 19 | expecti(15 >> 3, 1); 20 | expecti(8 >> 2, 2); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /tests/cast.c: -------------------------------------------------------------------------------- 1 | // casts 2 | 3 | int main(void) { 4 | expecti((int)1, 1); 5 | expectf((float)2, 2.0); 6 | expectd((double)3, 3.0); 7 | 8 | int a[3]; 9 | *(int *)(a + 2) = 1024; 10 | expecti(a[2], 1024); 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /tests/cgoto.c: -------------------------------------------------------------------------------- 1 | // labels as values (computed goto) 2 | 3 | int main(void) { 4 | // implement a small dispatch table of instructions for a mini 5 | // state machine, to test computed goto 6 | 7 | // test state 8 | int instruction_0_state = 0; 9 | int instruction_1_state = 0; 10 | int instruction_2_state = 0; 11 | 12 | unsigned char bytecode[] = {0x01, 0x05, 0x01, 0x02, 0x02, 0x03}; 13 | unsigned char *pc = bytecode; 14 | 15 | void *dispatch[] = { 16 | 0, 17 | &&instruction_0, 18 | &&instruction_1, 19 | &&instruction_2 20 | }; 21 | 22 | #define DISPATCH(INDEX) \ 23 | do { \ 24 | pc += (INDEX); \ 25 | goto *dispatch[*pc]; \ 26 | } while (0) 27 | 28 | // machine loop 29 | do { 30 | 31 | instruction_0: 32 | instruction_0_state += *(pc + 1); 33 | DISPATCH(2); 34 | 35 | instruction_1: 36 | instruction_1_state ++; 37 | DISPATCH(1); 38 | 39 | instruction_2: 40 | instruction_2_state --; 41 | break; 42 | 43 | } while (1); 44 | 45 | expecti(instruction_0_state, 7); 46 | expecti(instruction_1_state, 1); 47 | expecti(instruction_2_state, -1); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /tests/compare.c: -------------------------------------------------------------------------------- 1 | // comparison 2 | 3 | int main(void) { 4 | expecti(1 < 2, 1); 5 | expecti(1 > 2, 0); 6 | expecti(1 == 1, 1); 7 | expecti(1 == 2, 0); 8 | expecti(1 <= 2, 1); 9 | expecti(2 <= 2, 1); 10 | expecti(2 <= 1, 0); 11 | expecti(1 >= 2, 0); 12 | expecti(2 >= 2, 1); 13 | expecti(2 >= 1, 1); 14 | expecti(1 != 1, 0); 15 | expecti(1 != 0, 1); 16 | expecti(1.0f == 1.0f, 1); 17 | expecti(1.0f == 2.0f, 0); 18 | expecti(1.0f != 1.0f, 0); 19 | expecti(1.0f != 2.0f, 1); 20 | expecti(1.0 == 1.0f, 1); 21 | expecti(1.0 == 2.0f, 0); 22 | expecti(1.0 != 1.0f, 0); 23 | expecti(1.0 != 2.0f, 1); 24 | expecti(1.0f == 1.0, 1); 25 | expecti(1.0f == 2.0, 0); 26 | expecti(1.0f != 1.0, 0); 27 | expecti(1.0f != 2.0, 1); 28 | expecti(1.0 == 1.0, 1); 29 | expecti(1.0 == 2.0, 0); 30 | expecti(1.0 != 1.0, 0); 31 | expecti(1.0 != 2.0, 1); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /tests/compound.c: -------------------------------------------------------------------------------- 1 | // compound assignment 2 | 3 | int main(void) { 4 | int a = 5; 5 | expecti((a += 5), 10); 6 | expecti((a -= 5), 5); 7 | expecti((a *= 5), 25); 8 | expecti((a /= 5), 5); 9 | expecti((a %= 3), 2); 10 | 11 | int b = 14; 12 | expecti((b &= 7), 6); 13 | expecti((b |= 8), 14); 14 | expecti((b ^= 3), 13); 15 | expecti((b <<= 2), 52); 16 | expecti((b >>= 2), 13); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /tests/control.c: -------------------------------------------------------------------------------- 1 | // control flow 2 | 3 | int if1(void) { 4 | if (1) { 5 | return 1; 6 | } 7 | return 0; 8 | } 9 | 10 | int if2(void) { 11 | if (0) { 12 | return 0; 13 | } 14 | return 2; 15 | } 16 | 17 | int if3(void) { 18 | if (1) { 19 | return 3; 20 | } else { 21 | return 0; 22 | } 23 | return 0; 24 | } 25 | 26 | int if4(void) { 27 | if (0) { 28 | return 0; 29 | } else { 30 | return 4; 31 | } 32 | return 0; 33 | } 34 | 35 | int if5(void) { 36 | if (1) return 5; 37 | return 0; 38 | } 39 | 40 | int if6(void) { 41 | if (0) return 0; 42 | return 6; 43 | } 44 | 45 | int if7(void) { 46 | if (1) return 7; 47 | else return 0; 48 | return 0; 49 | } 50 | 51 | int if8(void) { 52 | if (0) return 0; 53 | else return 8; 54 | return 0; 55 | } 56 | 57 | int if9(void) { 58 | // 0.5 evaluates true 59 | if (0.5) return 9; 60 | else return 0; 61 | } 62 | 63 | int main(void) { 64 | int i; 65 | int j; 66 | 67 | expecti(if1(), 1); 68 | expecti(if2(), 2); 69 | expecti(if3(), 3); 70 | expecti(if4(), 4); 71 | expecti(if5(), 5); 72 | expecti(if6(), 6); 73 | expecti(if7(), 7); 74 | expecti(if8(), 8); 75 | expecti(if9(), 9); 76 | 77 | // for control 78 | j = 0; 79 | for (i = 0; i < 5; i++) 80 | j = j + i; 81 | expecti(j, 10); 82 | 83 | j = 0; 84 | for (i = 0; i < 5; i++) { 85 | j = j + i; 86 | } 87 | expecti(j, 10); 88 | 89 | j = 0; 90 | for (i = 0; i < 100; i++) { 91 | if (i < 5) 92 | continue; 93 | if (i == 9) 94 | break; 95 | j += i; 96 | } 97 | expecti(j, 5 + 6 + 7 + 8); 98 | 99 | i = 0; 100 | for (; 0.5;) { 101 | i = 1337; 102 | break; 103 | } 104 | expecti(i, 1337); 105 | 106 | // while control 107 | i = 0; 108 | j = 0; 109 | while (i <= 100) 110 | j = j + i++; 111 | expecti(j, 5050); 112 | 113 | i = 0; 114 | j = 1; 115 | while (i <= 100) 116 | j = j + i++; 117 | expecti(j, 5051); 118 | 119 | i = 0; 120 | j = 0; 121 | while (i < 10) { 122 | if (i++ < 5) 123 | continue; 124 | j += i; 125 | if (i == 9) 126 | break; 127 | } 128 | expecti(j, 6 + 7 + 8 + 9); 129 | 130 | i = 0; 131 | while (0.5) { 132 | i = 1337; 133 | break; 134 | } 135 | expecti(i, 1337); 136 | 137 | // do control 138 | i = 0; 139 | j = 0; 140 | do { 141 | j = j + i++; 142 | } while (i <= 100); 143 | expecti(j, 5050); 144 | 145 | i = 0; 146 | do { i = 1337; } while (0); 147 | expecti(i, 1337); 148 | 149 | i = 0; 150 | j = 0; 151 | do { 152 | if (i++ < 5) 153 | continue; 154 | j += i; 155 | if (i == 9) 156 | break; 157 | } while (i < 10); 158 | expecti(j, 6 + 7 + 8 + 9); 159 | expecti(i, 9); 160 | 161 | i = 0; 162 | do { i++; break; } while (0.5); 163 | expecti(i, 1); 164 | 165 | // switch control 166 | i = 0; 167 | switch (1 + 2) { 168 | case 0: 169 | expecti(0, 1); 170 | case 3: 171 | i = 3; 172 | break; 173 | case 1: 174 | expecti(0, 1); 175 | } 176 | expecti(i, 3); 177 | 178 | i = 0; 179 | switch(1) { 180 | case 0: i++; 181 | case 1: i++; 182 | case 2: i++; 183 | case 3: i++; 184 | } 185 | expecti(i, 3); 186 | 187 | i = 0; 188 | switch (1024) { 189 | case 0: i++; 190 | default: 191 | i = 128; 192 | } 193 | expecti(i, 128); 194 | 195 | i = 0; 196 | switch (1024) { 197 | case 0: i++; 198 | } 199 | expecti(i, 0); 200 | 201 | i = 1024; 202 | switch (3) { 203 | i++; 204 | } 205 | 206 | switch (1337) { 207 | case 1 ... 100: 208 | expecti(1, 0); 209 | case 101: 210 | expecti(1, 0); 211 | case 102 ... 1337: 212 | break; 213 | default: 214 | expecti(1, 0); 215 | } 216 | 217 | expecti(i, 1024); 218 | 219 | i = 0; 220 | j = 1024; 221 | switch (j % 8) { 222 | case 0: do { i++; 223 | case 7: i++; 224 | case 6: i++; 225 | case 5: i++; 226 | case 4: i++; 227 | case 3: i++; 228 | case 2: i++; 229 | case 1: i++; 230 | } while ((j -= 8) > 0); 231 | } 232 | expecti(i, 1024); 233 | 234 | // goto control 235 | j = 0; 236 | goto A; 237 | j = 5; 238 | A: expecti(j, 0); 239 | i = 0; 240 | j = 0; 241 | B: if (i > 10) 242 | goto C; 243 | j += i++; 244 | goto B; 245 | C: if (i > 11) 246 | goto D; 247 | expecti(j, 55); 248 | i++; 249 | goto B; 250 | D: 251 | expecti(i, 12); 252 | expecti(j, 55); 253 | 254 | // logical or control flow 255 | expecti(0 || 3, 1); 256 | expecti(5 || 0, 1); 257 | expecti(0 || 0, 0); 258 | 259 | // empty expressions 260 | for (;;) 261 | break; 262 | 263 | for (i = 0; i < 50; i++) 264 | ; 265 | 266 | i = 0; 267 | while (i++ < 50) 268 | ; 269 | 270 | i = 0; 271 | do 1; while (i++ < 50); 272 | i = 0; 273 | do; while (i++ < 50); 274 | 275 | switch (1) 276 | ; 277 | 278 | i = ((0.5) ? 1 : 0); 279 | expecti(i, 1); 280 | 281 | // computed goto 282 | void *Q[] = { &&__a, &&__b, &&__c, &&__d }; 283 | int _ = 0; 284 | goto *Q[0]; 285 | _ = 100; 286 | 287 | __a: 288 | if (_ == 5) 289 | return 0; 290 | expecti(_, 0); 291 | _ = 1; 292 | goto *Q[2]; 293 | _ = 2; 294 | 295 | __b: 296 | expecti(_, -1); 297 | _ = 5; 298 | goto *Q[3]; 299 | _ = 0; 300 | 301 | __c: 302 | expecti(_, 1); 303 | _ = -1; 304 | goto *Q[1]; 305 | _ = 3; 306 | 307 | __d: 308 | expecti(_, 5); 309 | goto **Q; 310 | 311 | 312 | return 1; // error 313 | } 314 | -------------------------------------------------------------------------------- /tests/dl.c: -------------------------------------------------------------------------------- 1 | // dynamic loading 2 | #include 3 | 4 | // should be good for the next ten thousand years :P 5 | #define SOMAX 128 6 | 7 | int main(void) { 8 | int so = 0; 9 | char buffer[32]; 10 | void *handle = dlopen("libc.so", 1); 11 | 12 | if (!handle) { 13 | for (so = 0; so < SOMAX; so++) { 14 | snprintf(buffer, sizeof(buffer), "libc.so.%d", so); 15 | if ((handle = dlopen(buffer, 1))) 16 | break; 17 | } 18 | } 19 | 20 | if (!handle) { 21 | printf("failed to load libc\n"); 22 | return 1; 23 | } 24 | 25 | // test must return 0 to succeed 26 | int (*a)(int) = dlsym(handle, "exit"); 27 | a(0); 28 | 29 | return 1; 30 | } 31 | -------------------------------------------------------------------------------- /tests/enum.c: -------------------------------------------------------------------------------- 1 | // enumerations 2 | 3 | enum { 4 | A, 5 | B, 6 | C 7 | }; 8 | 9 | enum { 10 | D, 11 | E, 12 | F 13 | }; 14 | 15 | int main(void) { 16 | expecti(A, 0); 17 | expecti(B, 1); 18 | expecti(C, 2); 19 | expecti(D, 0); 20 | expecti(E, 1); 21 | expecti(F, 2); 22 | 23 | enum { G } enum1; 24 | enum { H }; 25 | 26 | expecti(G, 0); 27 | expecti(H, 0); 28 | 29 | enum named { 30 | I, 31 | J, 32 | K 33 | }; 34 | 35 | enum named enum2 = I; 36 | expecti(enum2, 0); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /tests/es.c: -------------------------------------------------------------------------------- 1 | // expression statements 2 | 3 | #define maxint(A, B) \ 4 | ({ int a = (A), b = (B); a > b ? a : b; }) 5 | 6 | int main(void) { 7 | 8 | expecti(({ 'a'; 1; 64; }), 64); 9 | 10 | expecti( 11 | ({ 12 | int a = 10; 13 | a; 14 | }), 10 15 | ); 16 | 17 | expecti( 18 | ({ 19 | int i = 0; 20 | for (; i < 10; i++) 21 | ; 22 | i; 23 | }), 10 24 | ); 25 | 26 | expecti(maxint(100, 5), 100); 27 | 28 | expecti(({ (int){1}; }), 1); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /tests/extern.c: -------------------------------------------------------------------------------- 1 | // external linkage 2 | 3 | extern int expecti(int, int); 4 | extern int external_1; 5 | int extern external_2; 6 | 7 | int main(void) { 8 | expecti(external_1, 1337); 9 | expecti(external_2, 7331); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /tests/float.c: -------------------------------------------------------------------------------- 1 | // floats 2 | 3 | float ffunc1(float arg) { return arg; } 4 | float ffunc2(double arg) { return arg; } 5 | float ffunc3(int arg) { return arg; } 6 | double dfunc1(float arg) { return arg; } 7 | double dfunc2(double arg) { return arg; } 8 | double dfunc3(int arg) { return arg; } 9 | 10 | // deal with recursive calls for floats / doubles 11 | // requires stack alignment on some architectures 12 | // to properly work. 13 | float frecurse(float a) { 14 | if (a < 10) 15 | return a; 16 | return frecurse(3.14); 17 | } 18 | 19 | double drecurse(double a) { 20 | if (a < 10) 21 | return a; 22 | return drecurse(6.28); 23 | } 24 | 25 | int main(void) { 26 | // all float 27 | expectf(1.0, 1.0); 28 | expectf(1.0 + 0.5, 1.5); 29 | expectf(1.0 - 0.5, 0.5); 30 | expectf(1.0 * 2.0, 2.0); 31 | expectf(1.0 / 4.0, 0.25); 32 | 33 | // float and int 34 | expectf(1.0, 1.0); 35 | expectf(1.0 + 1, 2.0); 36 | expectf(1.0 - 1, 0.0); 37 | expectf(1.0 * 2, 2.0); 38 | expectf(1.0 / 4, 0.25); 39 | 40 | expectf(ffunc1(3.14f), 3.14f); 41 | expectf(ffunc1(3.0f), 3.0f); 42 | expectf(ffunc2(3.14f), 3.14f); 43 | expectf(ffunc2(3.0f), 3.0f); 44 | expectf(ffunc3(3.14f), 3.0f); 45 | expectf(ffunc3(3), 3); 46 | expectd(dfunc1(1.0), 1.0); 47 | expectd(dfunc1(10.0), 10.0); 48 | expectd(dfunc2(2.0), 2.0); 49 | expectd(dfunc2(10), 10.0); 50 | expectd(dfunc3(11.5), 11.0); 51 | expectd(dfunc3(10), 10.0); 52 | // Bug: these are still broken 53 | //expectf(frecurse(1024), 3.14); 54 | //expectd(drecurse(1024), 6.28); 55 | float a = 1024.0f; 56 | float b = a; 57 | expectf(a, 1024.0f); 58 | expectf(b, 1024.0f); 59 | 60 | double c = 2048.0; 61 | double d = c; 62 | expectd(c, 2048.0); 63 | expectd(d, 2048.0); 64 | 65 | expectf(0.7, .7); 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /tests/function.c: -------------------------------------------------------------------------------- 1 | // functions 2 | 3 | int i1() { return 42; } 4 | int i2(void) { return 42; } 5 | 6 | int splat(int a, int b, int c, int d, int e, int f) { 7 | expecti(a, 1); 8 | expecti(b, 2); 9 | expecti(c, 3); 10 | expecti(d, 4); 11 | expecti(e, 5); 12 | expecti(f, 6); 13 | } 14 | 15 | int deref(int *a) { 16 | return *a; 17 | } 18 | 19 | int proto1(); 20 | int proto1() { return 1024; } 21 | 22 | int proto2(int a, int b); 23 | int proto2(int a, int b) { 24 | return a + b; 25 | } 26 | 27 | void proto3(int a, ...); 28 | void proto3(int a, ...) { 29 | expecti(a, 1024); 30 | } 31 | 32 | void ignore(void) { 33 | return; 34 | } 35 | 36 | void ___func___(void) { 37 | expectstr(__func__, "___func___"); 38 | } 39 | 40 | int funptr1(void) { 41 | return 1024; 42 | } 43 | 44 | int funptr2(int a) { 45 | return funptr1() * 2; 46 | } 47 | 48 | float funptr3(float a) { 49 | return a * 2; 50 | } 51 | 52 | int funptr4(int (*callback)(void), int *data) { 53 | *data = callback(); 54 | return *data; 55 | } 56 | 57 | // emptyies 58 | void empty1(void) { 59 | // nothing to see here 60 | } 61 | 62 | void empty2(void) { 63 | // empty semicolons 64 | ;;; 65 | } 66 | 67 | int main(void) { 68 | expecti(i1(), 42); 69 | expecti(i2(), 42); 70 | 71 | int a = 1024; 72 | expecti(deref(&a), 1024); 73 | expecti(proto1(), 1024); 74 | expecti(proto2(512,512), 1024); 75 | 76 | proto3(1024); 77 | splat(1, 2, 3, 4, 5, 6); 78 | 79 | ignore(); 80 | ___func___(); 81 | 82 | // function pointer tests 83 | int (*ptr1)(void) = funptr1; 84 | int (*ptr2)(int) = funptr2; 85 | float (*ptr3)(float) = funptr3; 86 | int (*ptr4)(int(*)(void),int*) = funptr4; 87 | 88 | expecti(ptr1(), 1024); 89 | expecti(ptr2(a), 2048); 90 | expecti(ptr4(ptr1,&a), 1024); 91 | expecti(a, 1024); 92 | expectf(ptr3(3.14), 6.28); 93 | 94 | empty1(); 95 | empty2(); 96 | 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /tests/global.c: -------------------------------------------------------------------------------- 1 | // global variables 2 | 3 | int a = 1024; 4 | int *b = &a; 5 | 6 | int c[10]; 7 | int d[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 8 | 9 | int e, f; 10 | int g, h = 10; 11 | int i = 11, j; 12 | 13 | char k[] = "hello"; 14 | char *l = "world"; 15 | 16 | long m = 32; 17 | int *n = &(int) { 64 }; 18 | 19 | int main(void) { 20 | expecti(a, 1024); 21 | 22 | // can write to global? 23 | a = 2048; 24 | expecti(a, 2048); 25 | expecti(*b, 2048); 26 | 27 | c[1] = 2; 28 | expecti(c[1], 2); 29 | expecti(d[1], 2); 30 | 31 | e = 7; 32 | f = 8; 33 | expecti(e, 7); 34 | expecti(f, 8); 35 | g = 9; 36 | expecti(g, 9); 37 | expecti(h, 10); 38 | expecti(i, 11); 39 | j = 12; 40 | expecti(j, 12); 41 | 42 | expectstr(k, "hello"); 43 | expectstr(l, "world"); 44 | 45 | expectl(m, 32); 46 | expectl(*n, 64); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | /tests/ 2 | 3 |

/tests/

4 | 43 | 44 | -------------------------------------------------------------------------------- /tests/init.c: -------------------------------------------------------------------------------- 1 | // initializers 2 | 3 | void testi(int *recieved, int *wanted, int length) { 4 | for (int i = 0; i < length; i++) 5 | expecti(recieved[i], wanted[i]); 6 | } 7 | 8 | void tests(short *recieved, short *wanted, int length) { 9 | for (int i = 0; i < length; i++) 10 | expects(recieved[i], wanted[i]); 11 | } 12 | 13 | void testarray(void) { 14 | int a[] = { 1, 2, 3 }; 15 | int b[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 16 | int c[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; 17 | int d[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 18 | int e[] = { 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0 }; 19 | int f[4][3] = { { 1 }, { 2 }, { 3 }, { 4 } }; 20 | 21 | expecti(a[0], 1); 22 | expecti(a[1], 2); 23 | expecti(a[2], 3); 24 | 25 | testi(b, c, 9); 26 | testi(c, d, 9); 27 | testi(e, f, 12); 28 | 29 | short g[] = { 30 | 1, 0, 0, 0, 0, 31 | 0, 2, 3, 0, 0, 32 | 0, 0, 4, 5, 6 33 | }; 34 | 35 | short h[4][3][2] = { 36 | { 1 }, 37 | { 2, 3 }, 38 | { 4, 5, 6 } 39 | }; 40 | 41 | tests(g, h, 15); 42 | } 43 | 44 | void teststruct(void) { 45 | int a[] = { 46 | 1, 0, 0, 0, 47 | 2, 0, 0, 0 48 | }; 49 | 50 | struct { 51 | int a[3]; 52 | int b; 53 | } data[] = { { 1 }, 2 }; 54 | 55 | testi(&data, a, 8); 56 | } 57 | 58 | void testnesting(void) { 59 | struct { 60 | struct { 61 | struct { 62 | int a; 63 | int b; 64 | } a; 65 | 66 | struct { 67 | char a[8]; 68 | } b; 69 | } a; 70 | } data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 71 | 72 | expecti(data.a.a.a, 1); 73 | expecti(data.a.a.b, 2); 74 | expecti(data.a.b.a[0], 3); 75 | expecti(data.a.b.a[1], 4); 76 | expecti(data.a.b.a[2], 5); 77 | expecti(data.a.b.a[3], 6); 78 | expecti(data.a.b.a[4], 7); 79 | expecti(data.a.b.a[5], 8); 80 | expecti(data.a.b.a[6], 9); 81 | expecti(data.a.b.a[7], 10); 82 | } 83 | 84 | void testdesignated(void) { 85 | struct { int a, b, c; } a = { 86 | .a = 1024, 87 | .b = 2048, 88 | .c = 4096, 89 | }; 90 | 91 | struct { int a, b, c; } b = { 92 | .c = 4096, 93 | .b = 2048, 94 | .a = 1024 95 | }; 96 | 97 | struct { int a, b, c; } c = { 98 | .b = 2048, 99 | 4096, // should be c 100 | .a = 1024 101 | }; 102 | 103 | expecti(a.a, 1024); 104 | expecti(a.b, 2048); 105 | expecti(a.c, 4096); 106 | expecti(b.a, 1024); 107 | expecti(b.b, 2048); 108 | expecti(b.c, 4096); 109 | expecti(c.a, 1024); 110 | expecti(c.b, 2048); 111 | expecti(c.c, 4096); 112 | 113 | // array designated initializers 114 | int array[3] = { [1] = 1024 }; 115 | expecti(array[0], 0); 116 | expecti(array[1], 1024); 117 | expecti(array[2], 0); 118 | 119 | // for structs too 120 | struct { 121 | int a, b; 122 | } data[2] = { [1] = { 1, 2 } }; 123 | 124 | expecti(data[1].a, 1); 125 | expecti(data[1].b, 2); 126 | expecti(data[0].a, 0); 127 | expecti(data[0].b, 0); 128 | 129 | // splatted too 130 | struct { 131 | int a, b; 132 | } data2[3] = { [1] = 10, 20, 30, 40 }; 133 | expecti(data2[0].a, 0); 134 | expecti(data2[0].b, 0); 135 | expecti(data2[1].a, 10); 136 | expecti(data2[1].b, 20); 137 | expecti(data2[2].a, 30); 138 | expecti(data2[2].b, 40); 139 | 140 | struct { 141 | struct { 142 | int a, b; 143 | } c[3]; 144 | } again[] = { 145 | [1].c[0].b = 10, 20, 30, 40, 50, 146 | [0].c[2].b = 60, 70 147 | }; 148 | expecti(10, again[1].c[0].b); 149 | expecti(20, again[1].c[1].a); 150 | expecti(30, again[1].c[1].b); 151 | expecti(40, again[1].c[2].a); 152 | expecti(50, again[1].c[2].b); 153 | expecti(60, again[0].c[2].b); 154 | expecti(70, again[1].c[0].a); 155 | 156 | int A[][3] = { [0][0] = 10, [1][0] = 20 }; 157 | struct { int a, b[3]; } B = { .a = 10, .b[0] = 20, .b[1] = 30 }; 158 | 159 | expecti(A[0][0], 10); 160 | expecti(A[1][0], 20); 161 | expecti(B.a, 10); 162 | expecti(B.b[0], 20); 163 | expecti(B.b[1], 30); 164 | expecti(B.b[2], 0); 165 | } 166 | 167 | void testorder(void) { 168 | int order[4] = { [2] = 30, [0] = 10, 20 }; 169 | 170 | expecti(order[0], 10); 171 | expecti(order[1], 20); 172 | expecti(order[2], 30); 173 | } 174 | 175 | void testzero(void) { 176 | struct { int a, b; } a = { 1024 }; 177 | struct { int a, b; } b = { .b = 1024 }; 178 | 179 | expecti(a.a, 1024); 180 | expecti(a.b, 0); 181 | expecti(b.a, 0); 182 | expecti(b.b, 1024); 183 | } 184 | 185 | void testtypedef(void) { 186 | typedef int array[]; 187 | array a = { 1, 2, 3 }; 188 | array b = { 4, 5, 6 }; 189 | 190 | expecti(sizeof(a) / sizeof(*a), 3); 191 | expecti(sizeof(b) / sizeof(*b), 3); 192 | 193 | expecti(a[0], 1); 194 | expecti(a[1], 2); 195 | expecti(a[2], 3); 196 | expecti(b[0], 4); 197 | expecti(b[1], 5); 198 | expecti(b[2], 6); 199 | } 200 | 201 | int main(void) { 202 | testarray(); 203 | testnesting(); 204 | teststruct(); 205 | testdesignated(); 206 | testzero(); 207 | testtypedef(); 208 | testorder(); 209 | 210 | int primitive = { 1024 }; 211 | expecti(primitive, 1024); 212 | 213 | // test odd string initializers 214 | char f[] = "abc"; expectstr(f, "abc"); 215 | char g[] = { "cba" }; expectstr(g, "cba"); 216 | 217 | return 0; 218 | } 219 | -------------------------------------------------------------------------------- /tests/int.c: -------------------------------------------------------------------------------- 1 | // integers 2 | 3 | int main(void) { 4 | short a = 100; 5 | short int b = 150; 6 | long c = 2048; 7 | long int d = 4096; 8 | int e = 214748364; 9 | 10 | expects(a + b, 250); 11 | expects(a + 100, 200); 12 | 13 | expectl(c, 2048); 14 | expectl(d * 2, 8192); 15 | expectl(100L, 100L); 16 | 17 | expectl(922337203685477807, 922337203685477807); 18 | expectl(922337203685477806 + 1, 922337203685477807); 19 | 20 | expecti(e, 214748364); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /tests/kandr.c: -------------------------------------------------------------------------------- 1 | // K&R C 2 | 3 | #pragma warning_disable 4 | 5 | // implicit integer 6 | function() { 7 | return 4; 8 | } 9 | 10 | int main(void) { 11 | expecti(function(), 4); 12 | expecti(defined_later(), 1337); 13 | } 14 | 15 | defined_later() { 16 | // this is defined later, but main can call into it 17 | // since K&R doesn't care about declarations 18 | 19 | return 1337; 20 | } 21 | 22 | #pragma warning_enable 23 | -------------------------------------------------------------------------------- /tests/line.c: -------------------------------------------------------------------------------- 1 | // line continuation 2 | 3 | int \ 4 | main \ 5 | ( \ 6 | void // \ 7 | \ 8 | // one empty space to compensate 9 | ) { \ 10 | int \ 11 | a \ 12 | = \ 13 | 0, \ 14 | *b \ 15 | = \ 16 | &a; \ 17 | 18 | expecti(*b, a); // line continuation should make the above 19 | // int a=0,*b=&a; 20 | 21 | /* \ 22 | * \ 23 | * \\ int *e=b; / 24 | */ 25 | 26 | // would error if int *e made it as code 27 | int e = 0; // \ 28 | comments \ 29 | comments \ 30 | e = 1; 31 | 32 | expecti(e, 0); // error if e = 1 made it 33 | 34 | return e; // e == 0 (success) 35 | } 36 | -------------------------------------------------------------------------------- /tests/literal.c: -------------------------------------------------------------------------------- 1 | // literals 2 | 3 | struct s1 { 4 | int a; 5 | }; 6 | 7 | struct s2 { 8 | int a; 9 | struct s3 { 10 | int a[2]; 11 | } *b; 12 | }; 13 | 14 | 15 | int a = (int) { 42 }; 16 | int *b = &(int) { 42 }; 17 | struct s1 *c = &(struct s1) { 42 }; 18 | struct s2 *d = &(struct s2) { 42 , &(struct s3) { 42, 42 } }; 19 | 20 | int main(void) { 21 | expecti('a', 97); 22 | expecti('A', 65); 23 | 24 | //expecti('\0', 0); 25 | expecti('\a', 7); 26 | expecti('\b', 8); 27 | expecti('\t', 9); 28 | expecti('\n', 10); 29 | expecti('\v', 11); 30 | expecti('\f', 12); 31 | expecti('\r', 13); 32 | 33 | expecti('\7', 7); 34 | expecti('\17', 15); 35 | expecti('\235', -99); 36 | 37 | expecti('\x0', 0); 38 | expecti('\xff', -1); 39 | expecti('\x012', 18); 40 | 41 | 42 | expectstr("hello world", "hello world"); 43 | expecti("hello world"[5], ' '); 44 | expecti("hello world"[11], 0); // null terminator 45 | 46 | expectstr( 47 | (char []) { 'h', 'e', 'l', 'l', 'o', 0 }, 48 | "hello" 49 | ); 50 | 51 | expecti(L'c', 'c'); 52 | expectstr(L"butt", "butt"); 53 | 54 | // lexer could fail for 'L' so we need to ensure that it can be 55 | // used as an identifier still. 56 | int L = 1337; 57 | expecti(L, 1337); 58 | int L1 = L; 59 | expecti(L1, L); 60 | 61 | expecti(a, 42); 62 | expecti(*b, 42); 63 | expecti(c->a, 42); 64 | expecti(d->a, 42); 65 | expecti(d->b->a[0], 42); 66 | expecti(d->b->a[1], 42); 67 | 68 | // universal (unicode / host defined) 69 | expecti(L'\u0024', '$'); 70 | expecti(L'\U00000024', '$'); 71 | expectstr("\u0024", "$"); 72 | expectstr("\U00000024", "$"); 73 | 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /tests/number.c: -------------------------------------------------------------------------------- 1 | // numeric constants 2 | 3 | int main(void) { 4 | expecti(0x1, 1); 5 | expecti(0xf, 15); 6 | expecti(0xF, 15); 7 | 8 | expecti(3L, 3); 9 | expecti(3LL, 3); 10 | expecti(3UL, 3); 11 | expecti(3LU, 3); 12 | expecti(3ULL, 3); 13 | expecti(3LU, 3); 14 | expecti(3LLU, 3); 15 | expecti(3l, 3); 16 | expecti(3ll, 3); 17 | expecti(3ul, 3); 18 | expecti(3lu, 3); 19 | expecti(3ull, 3); 20 | expecti(3lu, 3); 21 | expecti(3llu, 3); 22 | 23 | expectf(1.0f, 1.0); 24 | expectf(1.2f, 1.2); 25 | expectf(1.0f, 1.0f); 26 | expectf(1.2f, 1.2f); 27 | 28 | expectd(3.14159265, 3.14159265); 29 | expectd(2e2, 200.0); 30 | expectd(1.55e1, 15.5); 31 | expectd(0x0.DE488631p8, 0xDE.488631); 32 | 33 | expectl(0xFL, 15L); 34 | expectl(0xFULL, 15ULL); 35 | 36 | expecti(0b1011, 11); 37 | expecti(0xe0, 224); 38 | expecti(0xE0, 224); 39 | 40 | expecti(sizeof(0xe0), 4); // should be integer type 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /tests/offsetof.c: -------------------------------------------------------------------------------- 1 | // offsetof 2 | 3 | #include 4 | 5 | struct test { 6 | int a; // 0 7 | int b; // 4 8 | int c; // 8 9 | char d; // 12 10 | short e; // 14 11 | int f; // 16 12 | }; 13 | 14 | int main(void) { 15 | expecti(offsetof(struct test, a), 0); 16 | expecti(offsetof(struct test, b), 4); 17 | expecti(offsetof(struct test, c), 8); 18 | expecti(offsetof(struct test, d), 12); 19 | expecti(offsetof(struct test, e), 14); 20 | expecti(offsetof(struct test, f), 16); 21 | 22 | // it should also be a valid integer constant expression 23 | int a[offsetof(struct test, b)]; 24 | expecti(sizeof(a), sizeof(int) * 4); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /tests/pointer.c: -------------------------------------------------------------------------------- 1 | // pointers 2 | 3 | int main(void) { 4 | int a = 1024; 5 | int *b = &a; 6 | char *c = "hi"; 7 | char *d = "hi" + 1; 8 | char e[] = "abc"; 9 | char *f = e + 2; 10 | char g[] = "abc"; 11 | 12 | *g = 32; 13 | expecti(*b, 1024); 14 | expecti(*c, 'h'); 15 | expecti(*d, 'i'); 16 | expecti(*f, 'c'); 17 | expecti(*g, 32); 18 | 19 | int aa[] = { 1, 2, 3 }; 20 | int *p = aa; 21 | expecti(*p, 1); p++; 22 | expecti(*p, 2); p++; 23 | expecti(*p, 3); 24 | expecti(*p, 3); p--; 25 | expecti(*p, 2); p--; 26 | expecti(*p, 1); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /tests/returnaddr.c: -------------------------------------------------------------------------------- 1 | // __builtin_return_address 2 | 3 | static void *a(void) { 4 | return __builtin_return_address(1); 5 | } 6 | 7 | static void *b(void) { 8 | expecti(__builtin_return_address(0), a()); 9 | return __builtin_return_address(0); 10 | } 11 | 12 | static void *c(void) { 13 | _1: 14 | void *this = b(); 15 | _2: 16 | expecti((&&_1 < this && this <= &&_2), 1); 17 | 18 | return this; 19 | } 20 | 21 | int main(void) { 22 | expecti(c() <= b(), 1); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /tests/scope.c: -------------------------------------------------------------------------------- 1 | // scope 2 | 3 | int main(void) { 4 | int i = 1024; 5 | 6 | { 7 | int i = 2048; 8 | expecti(i, 2048); 9 | i = 4096; 10 | } 11 | 12 | expecti(i, 1024); 13 | 14 | { 15 | int i = 4096; 16 | expecti(i, 4096); 17 | i = 2046; 18 | } 19 | 20 | expecti(i, 1024); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /tests/sizeof.c: -------------------------------------------------------------------------------- 1 | // sizeof operator 2 | 3 | int main(void) { 4 | expecti(sizeof(char), 1); 5 | expecti(sizeof(short), 2); 6 | expecti(sizeof(int), 4); 7 | expecti(sizeof(long), 8); 8 | expecti(sizeof(char*), 8); 9 | expecti(sizeof(short*), 8); 10 | expecti(sizeof(int*), 8); 11 | expecti(sizeof(long*), 8); 12 | 13 | expecti(sizeof(unsigned char), 1); 14 | expecti(sizeof(unsigned short), 2); 15 | expecti(sizeof(unsigned int), 4); 16 | expecti(sizeof(unsigned long), 8); 17 | 18 | expecti(sizeof 1, 4); 19 | expecti(sizeof 1L, 8); 20 | expecti(sizeof 1.0f, 4); 21 | expecti(sizeof 1.0, 8); 22 | expecti(sizeof 'a', 4); 23 | expecti(sizeof('b'), 4); 24 | 25 | expecti(sizeof(char[1]), 1); 26 | expecti(sizeof(char[2]), 2); 27 | expecti(sizeof(char[3]), 3); 28 | expecti(sizeof(char[1][10]), 10); 29 | expecti(sizeof(char[10][1]), 10); 30 | expecti(sizeof(char[10][10]), 100); 31 | expecti(sizeof(int[4][2]), 32); 32 | expecti(sizeof(int[2][4]), 32); 33 | 34 | char a[] = { 1, 2, 3 }; 35 | char b[] = "abc"; 36 | char *c[5]; 37 | char *(*d)[3]; 38 | 39 | expecti(sizeof(a), 3); 40 | expecti(sizeof(b), 4); 41 | expecti(sizeof(c), 40); 42 | expecti(sizeof(d), 8); 43 | expecti(sizeof(*d), 24); 44 | expecti(sizeof(**d), 8); 45 | expecti(sizeof(***d), 1); 46 | 47 | char _not_int_; 48 | expecti(sizeof((int)_not_int_), 4); // cast makes it sizeof(int) 49 | 50 | // the more complicated syntax cases 51 | expecti(sizeof(b[0]), 1); 52 | expecti(sizeof((b[0])), 1); 53 | expecti(sizeof((b)[0]), 1); 54 | expecti(sizeof(((b)[0])), 1); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /tests/statica.c: -------------------------------------------------------------------------------- 1 | // static assertions 2 | 3 | int main(void) { 4 | _Static_assert(1, "failed"); 5 | 6 | struct { 7 | _Static_assert(1, "failed"); 8 | } _; 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /tests/struct.c: -------------------------------------------------------------------------------- 1 | // structures 2 | 3 | struct A { 4 | int a; 5 | struct { 6 | char b; 7 | int c; 8 | } y; 9 | } A; 10 | 11 | struct B { 12 | int a; 13 | } B; 14 | 15 | struct C { 16 | int a; 17 | int b; 18 | } C; 19 | 20 | int main(void) { 21 | struct { 22 | int a; 23 | } a; 24 | a.a = 1024; 25 | expecti(a.a, 1024); 26 | 27 | struct { 28 | int a; 29 | int b; 30 | } b; 31 | b.a = 1024; 32 | b.b = 2048; 33 | expecti(b.a, 1024); 34 | expecti(b.b, 2048); 35 | 36 | struct { 37 | int a; 38 | struct { 39 | char b; 40 | int c; 41 | } b; 42 | } c; 43 | c.a = 1024; 44 | c.b.b = 32; 45 | c.b.c = 2048; 46 | expecti(c.a, 1024); 47 | expecti(c.b.b, 32); 48 | expecti(c.b.c, 2048); 49 | 50 | struct name1 { 51 | int a; 52 | struct { 53 | char b; 54 | int c; 55 | } b; 56 | }; 57 | struct name1 d; 58 | d.a = 16; 59 | d.b.b = 32; 60 | d.b.c = 64; 61 | expecti(d.a, 16); 62 | expecti(d.b.b, 32); 63 | expecti(d.b.c, 64); 64 | 65 | struct name2 { 66 | int a; 67 | int b; 68 | } e; 69 | struct name2 *f = &e; 70 | 71 | // obj->ptr 72 | e.a = 128; 73 | expecti((*f).a, 128); 74 | 75 | // ptr->obj 76 | (*f).a = 256; 77 | expecti(e.a, 256); 78 | 79 | // again 80 | e.b = 64; 81 | expecti((*f).b, 64); 82 | 83 | (*f).b = 128; 84 | expecti(e.b, 128); 85 | 86 | // over read? 87 | struct { 88 | int a[3]; 89 | int b[3]; 90 | } g; 91 | g.a[0] = 1024; 92 | g.b[1] = 2048; 93 | expecti(g.a[0], 1024); 94 | expecti(g.b[1], 2048); 95 | expecti(g.a[4], 2048); // &g.a[4] == &g.b[0] 96 | 97 | A.a = 64; 98 | A.y.b = 65; 99 | A.y.c = 256; 100 | expecti(A.a, 64); 101 | expecti(A.y.b, 65); 102 | expecti(A.y.c, 256); 103 | 104 | struct B *h = &B; 105 | B.a = 128; 106 | expecti((*h).a, 128); 107 | expecti(B.a, 128); 108 | expecti(h->a, 128); 109 | 110 | h->a = 256; 111 | expecti((*h).a, 256); 112 | expecti(B.a, 256); 113 | expecti(h->a, 256); 114 | 115 | struct C i[3]; 116 | i[0].a = 32; 117 | expecti(i[0].a, 32); 118 | i[0].b = 64; 119 | expecti(i[0].b, 64); 120 | i[1].b = 128; 121 | expecti(i[1].b, 128); 122 | int *j = i; 123 | expecti(j[3], 128); // &j[3] == &i[1].b 124 | 125 | struct { char c; } k = { 'a' }; 126 | expecti(k.c, 'a'); 127 | 128 | struct { int a[3]; } l = { { 1, 2, 3 } }; 129 | expecti(l.a[0], 1); 130 | expecti(l.a[1], 2); 131 | expecti(l.a[2], 3); 132 | 133 | // unnamed shit 134 | struct { 135 | union { 136 | struct { 137 | int x; 138 | int y; 139 | }; 140 | struct { 141 | char c[8]; 142 | }; 143 | }; 144 | } m; 145 | m.x = 10; 146 | m.y = 20; 147 | expecti(m.c[0], 10); 148 | expecti(m.c[4], 20); 149 | 150 | // structure copy via assignment 151 | struct { 152 | int a; 153 | int b; 154 | int c; 155 | } X, Y, Z; 156 | X.a = 8; 157 | X.b = 16; 158 | X.c = 32; 159 | Y = X; 160 | Z.a = 64; 161 | Z.b = 128; 162 | Z.c = 256; 163 | expecti(Y.a, 8); 164 | expecti(Y.b, 16); 165 | expecti(Y.c, 32); 166 | Y = Z; 167 | expecti(Y.a, 64); 168 | expecti(Y.b, 128); 169 | expecti(Y.c, 256); 170 | 171 | // arrows 172 | struct cell { 173 | int value; 174 | struct cell *next; 175 | }; 176 | struct cell aa = { 10, 0 }; 177 | struct cell bb = { 20, &aa }; 178 | struct cell cc = { 30, &bb }; 179 | struct cell *dd = &cc; 180 | 181 | expecti(cc.value, 30); 182 | expecti(dd->value, 30); 183 | expecti(dd->next->value, 20); 184 | expecti(dd->next->next->value, 10); 185 | 186 | dd->value = 16; 187 | dd->next->value = 32; 188 | dd->next->next->value = 64; 189 | expecti(dd->value, 16); 190 | expecti(dd->next->value, 32); 191 | expecti(dd->next->next->value, 64); 192 | 193 | // addressing 194 | struct super { 195 | int a; 196 | struct { 197 | int b; 198 | } y; 199 | } poke = { 99, 100 }; 200 | 201 | int *poke1 = &poke.a; 202 | int *poke2 = &poke.y.b; 203 | 204 | expecti(*poke1, 99); 205 | expecti(*poke2, 100); 206 | expecti(*&poke.a, 99); 207 | expecti(*&poke.y.b, 100); 208 | 209 | struct super *inward = &poke; 210 | int *poke3 = &inward->a; 211 | int *poke4 = &inward->y.b; 212 | 213 | expecti(*poke3, 99); 214 | expecti(*poke4, 100); 215 | expecti(*&inward->a, 99); 216 | expecti(*&inward->y.b, 100); 217 | 218 | // incomplete in the opposite direction 219 | struct incomplete1; 220 | struct incomplete2 { 221 | struct incomplete1 *next; 222 | }; 223 | struct incomplete1 { 224 | int value; 225 | }; 226 | 227 | struct incomplete1 in1 = { 3 }; 228 | struct incomplete2 in2 = { &in1 }; 229 | 230 | expecti(in2.next->value, 3); 231 | 232 | struct { 233 | int x; 234 | } __a = { 235 | 1024 236 | }, *__b = &__a; 237 | int *__c = &__b->x; 238 | 239 | expecti(*__c, 1024); 240 | 241 | 242 | // bit fields 243 | union { 244 | int i; 245 | struct { 246 | int a: 5; 247 | int b: 5; 248 | }; 249 | } bitfield; 250 | bitfield.i = 0; 251 | bitfield.a = 20; 252 | bitfield.b = 15; 253 | expecti(bitfield.i, 500); // (15 << 5) + 20 == 500 254 | 255 | struct { 256 | char a:4; 257 | char b:4; 258 | } bitfield2 = { 5, 10 }; 259 | 260 | expecti(bitfield2.a, 5); 261 | expecti(bitfield2.b, 10); 262 | 263 | union { 264 | int a: 10; 265 | char b: 5; 266 | char c: 5; 267 | } bitfield3; 268 | 269 | bitfield3.a = 2; 270 | expecti(bitfield3.a, 2); 271 | expecti(bitfield3.b, 2); 272 | expecti(bitfield3.c, 2); 273 | 274 | struct __empty {}; 275 | expecti(sizeof(struct __empty), 0); 276 | 277 | // FAMS 278 | struct __fam0 { int a, b[]; }; 279 | struct __fam1 { int a, b[0]; }; 280 | 281 | expecti(sizeof(struct __fam0), 4); 282 | expecti(sizeof(struct __fam1), 4); 283 | 284 | struct __gccfam { int a[0]; }; 285 | expecti(sizeof(struct __gccfam), 0); 286 | 287 | struct __famoverwrite { int a, b[]; }; 288 | struct __famoverwrite OV = { 1, 2, 3, 4, 5 }; 289 | 290 | expecti(OV.b[0], 2); 291 | expecti(OV.b[1], 3); 292 | expecti(OV.b[2], 4); 293 | expecti(OV.b[3], 5); 294 | 295 | return 0; 296 | } 297 | -------------------------------------------------------------------------------- /tests/typeof.c: -------------------------------------------------------------------------------- 1 | // typeof keyword 2 | 3 | int main(void) { 4 | // basic usage of it 5 | typeof(int) a = 1024; 6 | expecti(a, 1024); 7 | 8 | typeof(a) b = 2048; 9 | expecti(b, 2048); 10 | 11 | __typeof__(int) aa = 1024; 12 | expecti(aa, 1024); 13 | 14 | __typeof__(aa) bb = 2048; 15 | expecti(bb, 2048); 16 | 17 | 18 | // arrays? 19 | char c[] = "hello"; 20 | typeof(c) d = "world"; 21 | 22 | expectstr(d, "world"); 23 | expecti(sizeof(d), 6); 24 | 25 | typeof(typeof (char *)[4]) odd; 26 | expecti(sizeof(odd)/sizeof(*odd), 4); 27 | 28 | 29 | char cc[] = "hello"; 30 | __typeof__(cc) dd = "world"; 31 | 32 | expectstr(dd, "world"); 33 | expecti(sizeof(dd), 6); 34 | 35 | __typeof__(__typeof__ (char *)[4]) oddd; 36 | expecti(sizeof(oddd)/sizeof(*oddd), 4); 37 | 38 | // struct union enum 39 | typeof(struct { int a; }) __1 = { .a = 1 }; 40 | typeof(union { int a; }) __2 = { .a = 1 }; 41 | typeof(enum { A1,B2 }) __3 = { B2 }; 42 | 43 | expecti(__1.a, 1); 44 | expecti(__2.a, 1); 45 | expecti(__3, B2); 46 | 47 | __typeof__(struct { int a; }) __11 = { .a = 1 }; 48 | __typeof__(union { int a; }) __22 = { .a = 1 }; 49 | __typeof__(enum { A11,B22 }) __33 = { B22 }; 50 | 51 | expecti(__11.a, 1); 52 | expecti(__22.a, 1); 53 | expecti(__33, B22); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /tests/types.c: -------------------------------------------------------------------------------- 1 | // types 2 | 3 | int main(void) { 4 | char a; 5 | short b; 6 | int c; 7 | long d; 8 | long long e; 9 | short int f; 10 | long int g; 11 | long long int f; 12 | long int long g; 13 | float h; 14 | double i; 15 | long double j; 16 | 17 | signed char k; 18 | signed short l; 19 | signed int m; 20 | signed long n; 21 | signed long long o; 22 | signed short int p; 23 | signed long int q; 24 | signed long long int r; 25 | 26 | unsigned char s; 27 | unsigned short t; 28 | unsigned int u; 29 | unsigned long v; 30 | unsigned long long w; 31 | unsigned short int x; 32 | unsigned long int y; 33 | unsigned long long int z; 34 | 35 | static A; 36 | auto B; 37 | register C; 38 | static int D; 39 | auto int E; 40 | register int F; 41 | 42 | int *G; 43 | int *H[5]; 44 | int (*I)[5]; 45 | expecti(sizeof(G), 8); 46 | expecti(sizeof(H), 40); 47 | expecti(sizeof(I), 8); 48 | 49 | int unsigned auto* const* const* J; 50 | 51 | typedef int K; 52 | K L = 5; 53 | expecti(L, 5); 54 | 55 | typedef K M[3]; 56 | M N = { 1, 2, 3 }; 57 | expecti(N[0], 1); 58 | expecti(N[1], 2); 59 | expecti(N[2], 3); 60 | 61 | typedef struct { int a; } O; 62 | O P; 63 | P.a = 64; 64 | expecti(P.a, 64); 65 | 66 | typedef int __take_precedence_1; 67 | typedef int __take_precedence_2; 68 | __take_precedence_1 __take_precedence_2 = 100; 69 | expecti(__take_precedence_2, 100); 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /tests/union.c: -------------------------------------------------------------------------------- 1 | // unions 2 | 3 | int global = 5; 4 | int *pointer = &global; 5 | 6 | int main(void) { 7 | union { 8 | int a; 9 | int b; 10 | } a = { 128 }; 11 | 12 | union { 13 | char a[4]; 14 | int b; 15 | } b = { .b = 0 }; 16 | 17 | b.a[1] = 1; 18 | 19 | union { 20 | char a[4]; 21 | int b; 22 | } c = { 0, 1, 0, 0 }; 23 | 24 | expecti(a.b, 128); 25 | expecti(b.b, 256); 26 | expecti(c.b, 256); 27 | 28 | expecti(*pointer, 5); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /tests/varargs.c: -------------------------------------------------------------------------------- 1 | // stdarg 2 | 3 | #include 4 | char buffer[1024]; 5 | 6 | void testi(int a, ...) { 7 | va_list ap; 8 | va_start(ap, a); 9 | expecti(a, 1); 10 | expecti(va_arg(ap, int), 2); 11 | expecti(va_arg(ap, int), 3); 12 | expecti(va_arg(ap, int), 4); 13 | expecti(va_arg(ap, int), 5); 14 | 15 | va_end(ap); 16 | } 17 | 18 | void testf(float a, ...) { 19 | va_list ap; 20 | va_start(ap, a); 21 | 22 | expectf(a, 1.0f); 23 | expectf(va_arg(ap, float), 2.0f); 24 | expectf(va_arg(ap, float), 4.0f); 25 | expectf(va_arg(ap, float), 8.0f); 26 | 27 | va_end(ap); 28 | } 29 | 30 | void testm(char *p, ...) { 31 | va_list ap; 32 | va_start(ap, p); 33 | 34 | expectstr(p, "hello world"); 35 | expectf (va_arg(ap, float), 3.14); 36 | expecti (va_arg(ap, int), 1024); 37 | expectstr(va_arg(ap, char *), "good bye world"); 38 | expecti (va_arg(ap, int), 2048); 39 | 40 | va_end(ap); 41 | } 42 | 43 | char *format(char *fmt, ...) { 44 | va_list ap; 45 | va_start(ap, fmt); 46 | vsprintf(buffer, fmt, ap); // fuck yeah 47 | va_end(ap); 48 | return buffer; 49 | } 50 | 51 | void testt(void) { 52 | expectstr(format(""), ""); // nothing 53 | expectstr(format("%d", 10), "10"); 54 | expectstr( 55 | format("%d,%.1f,%d,%.1f,%s", 1024, 3.14, 2048, 6.28, "hello world"), 56 | "1024,3.1,2048,6.3,hello world" 57 | ); 58 | } 59 | 60 | int main(void) { 61 | testi(1, 2, 3, 4, 5); 62 | testf(1.0f, 2.0f, 4.0f, 8.0f); 63 | testm("hello world", 3.14, 1024, "good bye world", 2048); 64 | testt(); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /tests/void.c: -------------------------------------------------------------------------------- 1 | // arithmetic on void 2 | 3 | int main(void) { 4 | expecti(sizeof(void), 1); 5 | expecti(sizeof(main), 8); // sizeof function == sizeof(&function) 6 | // i.e the function pointer for that 7 | // function (GCC extension) 8 | 9 | int a[] = { 1, 2, 3 }; 10 | void *p = (void*)a; 11 | 12 | expecti(*(int*)p, 1); p += 4; 13 | expecti(*(int*)p, 2); p += 4; 14 | expecti(*(int*)p, 3); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "util.h" 8 | 9 | #define MEMORY 0x8000000 10 | 11 | static unsigned char *memory_pool = NULL; 12 | static size_t memory_next = 0; 13 | 14 | static void memory_cleanup(void) { 15 | free(memory_pool); 16 | } 17 | 18 | void *memory_allocate(size_t bytes) { 19 | void *value; 20 | 21 | if (!memory_pool) { 22 | memory_pool = malloc(MEMORY); 23 | atexit(memory_cleanup); 24 | } 25 | 26 | if (memory_next > MEMORY) 27 | goto bail; 28 | 29 | value = &memory_pool[memory_next]; 30 | memory_next += bytes; 31 | 32 | if (memory_next > MEMORY) { 33 | bail: 34 | fprintf(stderr, "[lice] out of memory"); 35 | exit(EXIT_FAILURE); 36 | } 37 | 38 | return value; 39 | } 40 | 41 | struct string_s { 42 | char *buffer; 43 | int allocated; 44 | int length; 45 | }; 46 | 47 | static void string_reallocate(string_t *string) { 48 | int size = string->allocated * 2; 49 | char *buffer = memory_allocate(size); 50 | 51 | strcpy(buffer, string->buffer); 52 | string->buffer = buffer; 53 | string->allocated = size; 54 | } 55 | 56 | void string_catf(string_t *string, const char *fmt, ...) { 57 | va_list va; 58 | for (;;) { 59 | int left = string->allocated - string->length; 60 | int write; 61 | 62 | va_start(va, fmt); 63 | write = vsnprintf(string->buffer + string->length, left, fmt, va); 64 | va_end(va); 65 | 66 | if (left <= write) { 67 | string_reallocate(string); 68 | continue; 69 | } 70 | string->length += write; 71 | return; 72 | } 73 | } 74 | 75 | string_t *string_create(void) { 76 | string_t *string = memory_allocate(sizeof(string_t)); 77 | string->buffer = memory_allocate(8); 78 | string->allocated = 8; 79 | string->length = 0; 80 | string->buffer[0] = '\0'; 81 | return string; 82 | } 83 | 84 | char *string_buffer(string_t *string) { 85 | return string->buffer; 86 | } 87 | 88 | void string_cat(string_t *string, char ch) { 89 | if (string->allocated == (string->length + 1)) 90 | string_reallocate(string); 91 | string->buffer[string->length++] = ch; 92 | string->buffer[string->length] = '\0'; 93 | } 94 | 95 | char *string_quote(char *p) { 96 | string_t *string = string_create(); 97 | while (*p) { 98 | if (*p == '\"' || *p == '\\') 99 | string_catf(string, "\\%c", *p); 100 | else if (*p == '\n') 101 | string_catf(string, "\\n"); 102 | else 103 | string_cat(string, *p); 104 | p++; 105 | } 106 | return string->buffer; 107 | } 108 | 109 | size_t string_length(string_t *string) { 110 | return (string) ? string->length : 0; 111 | } 112 | 113 | typedef struct { 114 | char *key; 115 | void *value; 116 | } table_entry_t; 117 | 118 | void *table_create(void *parent) { 119 | table_t *table = memory_allocate(sizeof(table_t)); 120 | table->list = list_create(); 121 | table->parent = parent; 122 | 123 | return table; 124 | } 125 | 126 | void *table_find(table_t *table, const char *key) { 127 | for (; table; table = table->parent) { 128 | for (list_iterator_t *it = list_iterator(table->list); !list_iterator_end(it); ) { 129 | table_entry_t *entry = list_iterator_next(it); 130 | if (!strcmp(key, entry->key)) 131 | return entry->value; 132 | } 133 | } 134 | return NULL; 135 | } 136 | 137 | void table_insert(table_t *table, char *key, void *value) { 138 | table_entry_t *entry = memory_allocate(sizeof(table_entry_t)); 139 | entry->key = key; 140 | entry->value = value; 141 | 142 | list_push(table->list, entry); 143 | } 144 | 145 | void *table_parent(table_t *table) { 146 | return table->parent; 147 | } 148 | 149 | list_t *table_values(table_t *table) { 150 | list_t *list = list_create(); 151 | for (; table; table = table->parent) 152 | for (list_iterator_t *it = list_iterator(table->list); !list_iterator_end(it); ) 153 | list_push(list, ((table_entry_t*)list_iterator_next(it))->value); 154 | return list; 155 | } 156 | 157 | list_t *table_keys(table_t *table) { 158 | list_t *list = list_create(); 159 | for (; table; table = table->parent) 160 | for (list_iterator_t *it = list_iterator(table->list); !list_iterator_end(it); ) 161 | list_push(list, ((table_entry_t*)list_iterator_next(it))->key); 162 | return list; 163 | } 164 | 165 | pair_t *pair_create(void *first, void *second) { 166 | pair_t *pair = memory_allocate(sizeof(pair_t)); 167 | pair->first = first; 168 | pair->second = second; 169 | return pair; 170 | } 171 | 172 | int strcasecmp(const char *s1, const char *s2) { 173 | const unsigned char *u1 = (const unsigned char *)s1; 174 | const unsigned char *u2 = (const unsigned char *)s2; 175 | 176 | while (tolower(*u1) == tolower(*u2++)) 177 | if(*u1++ == '\0') 178 | return 0; 179 | return tolower(*u1) - tolower(*--u2); 180 | } 181 | 182 | int strncasecmp(const char *s1, const char *s2, size_t n) { 183 | const unsigned char *u1 = (const unsigned char *)s1; 184 | const unsigned char *u2 = (const unsigned char *)s2; 185 | 186 | if (!n) 187 | return 0; 188 | 189 | do { 190 | if (tolower(*u1) != tolower(*u2++)) 191 | return tolower(*u1) - tolower(*--u2); 192 | if (*u1++ == '\0') 193 | break; 194 | } while (--n != 0); 195 | 196 | return 0; 197 | } 198 | 199 | size_t getline(char **line, size_t *n, FILE *stream) { 200 | char *buf = NULL; 201 | char *p = buf; 202 | 203 | int size; 204 | int c; 205 | 206 | if (!line) 207 | return -1; 208 | if (!stream) 209 | return -1; 210 | if (!n) 211 | return -1; 212 | 213 | buf = *line; 214 | size = *n; 215 | 216 | if ((c = fgetc(stream)) == EOF) 217 | return -1; 218 | if (!buf) { 219 | buf = malloc(128); 220 | size = 128; 221 | } 222 | p = buf; 223 | while(c != EOF) { 224 | if ((p - buf) > (size - 1)) { 225 | size = size + 128; 226 | buf = realloc(buf, size); 227 | } 228 | *p++ = c; 229 | if (c == '\n') 230 | break; 231 | c = fgetc(stream); 232 | } 233 | 234 | *p++ = '\0'; 235 | *line = buf; 236 | *n = size; 237 | 238 | return p - buf - 1; 239 | } 240 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #ifndef GMCC_UTIL_HDR 2 | #define GMCC_UTIL_HDR 3 | #include 4 | #include 5 | 6 | #include "list.h" 7 | 8 | /* 9 | * Type: string_t 10 | * A type capable of representing a self-resizing string with 11 | * O(1) strlen. 12 | */ 13 | typedef struct string_s string_t; 14 | 15 | /* 16 | * Function: string_create 17 | * Create a string object 18 | */ 19 | string_t *string_create(void); 20 | 21 | /* 22 | * Function: string_buffer 23 | * Return the raw buffer of a string object 24 | */ 25 | char *string_buffer(string_t *string); 26 | 27 | /* 28 | * Function: string_cat 29 | * Append a character to a string object 30 | */ 31 | void string_cat(string_t *string, char ch); 32 | 33 | /* 34 | * Function: string_catf 35 | * Append a formatted string to a string object 36 | */ 37 | void string_catf(string_t *string, const char *fmt, ...); 38 | 39 | /* 40 | * Function: string_quote 41 | * Escape a string's quotes 42 | */ 43 | char *string_quote(char *p); 44 | 45 | /* 46 | * Function: string_length 47 | * Get the length of the given string 48 | */ 49 | size_t string_length(string_t *string); 50 | 51 | /* 52 | * Type: table_t 53 | * A key value associative table 54 | */ 55 | typedef struct table_s table_t; 56 | 57 | struct table_s { 58 | list_t *list; 59 | table_t *parent; 60 | }; 61 | 62 | /* 63 | * Function: table_create 64 | * Creates a table_t object 65 | */ 66 | void *table_create(void *parent); 67 | 68 | /* 69 | * Funciton: table_find 70 | * Searches for a given value in the table based on the 71 | * key associated with it. 72 | */ 73 | void *table_find(table_t *table, const char *key); 74 | 75 | /* 76 | * Function: table_insert 77 | * Inserts a value for the given key as an entry in the 78 | * table. 79 | */ 80 | void table_insert(table_t *table, char *key, void *value); 81 | 82 | /* 83 | * Function: table_parent 84 | * Returns the parent opaque object for the given table to 85 | * be used as the argument to a new table. 86 | */ 87 | void *table_parent(table_t *table); 88 | 89 | /* 90 | * Function: table_values 91 | * Generates a list of all the values in the table, useful for 92 | * iterating over the values. 93 | */ 94 | list_t *table_values(table_t *table); 95 | 96 | /* 97 | * Function: table_keys 98 | * Generate a list of all the keys in the table, useful for 99 | * iteration over the keys. 100 | */ 101 | list_t *table_keys(table_t *table); 102 | 103 | /* 104 | * Macro: SENTINEL_TABLE 105 | * Initialize an empty table in place 106 | */ 107 | #define SENTINEL_TABLE ((table_t) { \ 108 | .list = &SENTINEL_LIST, \ 109 | .parent = NULL \ 110 | }) 111 | 112 | 113 | #define MIN(A, B) (((A) < (B)) ? (A) : (B)) 114 | #define MAX(A, B) (((A) > (B)) ? (A) : (B)) 115 | 116 | /* 117 | * Function: memory_allocate 118 | * Allocate some memory 119 | */ 120 | void *memory_allocate(size_t bytes); 121 | 122 | /* 123 | * Structure: pair_t 124 | * A class container describing a pair 125 | */ 126 | typedef struct { 127 | /* Variable: first */ 128 | void *first; 129 | /* Variable: second */ 130 | void *second; 131 | } pair_t; 132 | 133 | /* 134 | * Function: pair_create 135 | * Used to create a . 136 | * 137 | * Parameters: 138 | * first - Pointer to first object 139 | * second - Pointer to second object 140 | * 141 | * Returns: 142 | * A pointer to a constructed containing first and last 143 | * pointers which point to the same address as the ones supplied 144 | * as parameters to this function. 145 | */ 146 | pair_t *pair_create(void *first, void *last); 147 | 148 | /* String utilities */ 149 | int strcasecmp(const char *s1, const char *s2); 150 | int strncasecmp(const char *s1, const char *s2, size_t n); 151 | size_t getline(char **line, size_t *n, FILE *stream); 152 | 153 | /* 154 | * Macro: bool_stringa 155 | * Returns a "true" or "false" for an expression that evaluates to a 156 | * boolean representation enforced with cast-to-bool `!!` 157 | */ 158 | #define bool_string(BOOL) \ 159 | ((!!(BOOL)) ? "true" : "false") 160 | 161 | #endif 162 | --------------------------------------------------------------------------------