#ifndef COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_ #define COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_ #include "libc/assert.h" #include "libc/bits/popcnt.h" #include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" #include "libc/calls/weirdtypes.h" #include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/fmt/fmt.h" #include "libc/fmt/itoa.h" #include "libc/limits.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.h" #include "libc/mem/mem.h" #include "libc/nexgen32e/bsf.h" #include "libc/nexgen32e/bsr.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/stdio/temp.h" #include "libc/str/str.h" #include "libc/time/struct/tm.h" #include "libc/time/time.h" #include "libc/unicode/unicode.h" #include "libc/x/x.h" #include "third_party/gdtoa/gdtoa.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ #pragma GCC diagnostic ignored "-Wswitch" typedef struct Asm Asm; typedef struct AsmOperand AsmOperand; typedef struct File File; typedef struct FpClassify FpClassify; typedef struct Hideset Hideset; typedef struct Member Member; typedef struct Node Node; typedef struct Obj Obj; typedef struct Relocation Relocation; typedef struct Relocation Relocation; typedef struct StaticAsm StaticAsm; typedef struct StringArray StringArray; typedef struct Token Token; typedef struct TokenStack TokenStack; typedef struct Type Type; // // strarray.c // struct StringArray { char **data; int capacity; int len; }; void strarray_push(StringArray *, char *); // // tokenize.c // typedef enum { TK_IDENT, // Identifiers TK_PUNCT, // Punctuators TK_KEYWORD, // Keywords TK_STR, // String literals TK_NUM, // Numeric literals TK_PP_NUM, // Preprocessing numbers TK_EOF, // End-of-file markers } TokenKind; struct File { char *name; int file_no; char *contents; // For #line directive char *display_name; int line_delta; }; struct thatispacked Token { Token *next; // Next token int len; // Token length int line_no; // Line number int line_delta; // Line number TokenKind kind; // Token kind bool at_bol; // True if this token is at beginning of line bool has_space; // True if this token follows a space character char *loc; // Token location Type *ty; // Used if TK_NUM or TK_STR File *file; // Source location char *filename; // Filename Hideset *hideset; // For macro expansion Token *origin; // If this is expanded from a macro, the original token union { int64_t val; // If kind is TK_NUM, its value long double fval; // If kind is TK_NUM, its value char *str; // String literal contents including terminating '\0' }; }; void error(char *, ...) __attribute__((__noreturn__, __format__(__printf__, 1, 2))); void error_at(char *, char *, ...) __attribute__((__noreturn__, __format__(__printf__, 2, 3))); void error_tok(Token *, char *, ...) __attribute__((__noreturn__, __format__(__printf__, 2, 3))); void warn_tok(Token *, char *, ...) __attribute__((__format__(__printf__, 2, 3))); File **get_input_files(void); File *new_file(char *, int, char *); Token *skip(Token *, char); Token *tokenize(File *); Token *tokenize_file(char *); Token *tokenize_string_literal(Token *, Type *); bool consume(Token **, Token *, char *, size_t); bool equal(Token *, char *, size_t); void convert_pp_tokens(Token *); void remove_backslash_newline(char *); void canonicalize_newline(char *); char *read_file(char *); int read_escaped_char(char **, char *); #define UNREACHABLE() error("internal error at %s:%d", __FILE__, __LINE__) #define EQUAL(T, S) equal(T, S, strlen(S)) #define CONSUME(R, T, S) consume(R, T, S, strlen(S)) // // preprocess.c // char *search_include_paths(char *); void init_macros(void); void define_macro(char *, char *); void undef_macro(char *); Token *preprocess(Token *); // // asm.c // #define kAsmImm 1 #define kAsmMem 2 #define kAsmReg 4 #define kAsmMmx 8 #define kAsmXmm 16 #define kAsmFpu 32 #define kAsmRaw 64 #define kAsmFlag 128 struct AsmOperand { uint8_t reg; uint8_t type; char flow; char x87mask; bool isused; int regmask; int predicate; char *str; Node *node; Token *tok; int64_t val; char **label; }; struct Asm { int n; char *str; Token *tok; AsmOperand ops[20]; bool isgnu; bool flagclob; uint8_t x87clob; uint16_t regclob; uint16_t xmmclob; }; struct StaticAsm { StaticAsm *next; Asm *body; }; extern StaticAsm *staticasms; Asm *asm_stmt(Token **, Token *); void flushln(void); void gen_addr(Node *); void gen_asm(Asm *); void gen_expr(Node *); void pop(char *); void popreg(char *); void print_loc(int64_t, int64_t); void push(void); void pushreg(char *); // // fpclassify.c // struct FpClassify { Node *node; int args[5]; }; void gen_fpclassify(FpClassify *); // // parse.c // // Variable or function struct Obj { Obj *next; char *name; // Variable name Type *ty; // Type Token *tok; // representative token bool is_local; // local or global/function int align; // alignment // Local variable int offset; // Global variable or function bool is_function; bool is_definition; bool is_static; bool is_weak; bool is_externally_visible; char *asmname; char *section; char *visibility; // Global variable bool is_tentative; bool is_string_literal; bool is_tls; char *init_data; Relocation *rel; // Function bool is_inline; bool is_aligned; bool is_noreturn; bool is_destructor; bool is_constructor; int stack_size; Obj *params; Node *body; Obj *locals; Obj *va_area; Obj *alloca_bottom; // Dead Code Elimination bool is_live; bool is_root; StringArray refs; }; // Global variable can be initialized either by a constant expression // or a pointer to another global variable. This struct represents the // latter. struct Relocation { Relocation *next; int offset; char **label; long addend; }; typedef enum { ND_NULL_EXPR, // Do nothing ND_ADD, // + ND_SUB, // - ND_MUL, // * ND_DIV, // / ND_NEG, // unary - ND_REM, // % ND_BINAND, // & ND_BINOR, // | ND_BINXOR, // ^ ND_SHL, // << ND_SHR, // >> ND_EQ, // == ND_NE, // != ND_LT, // < ND_LE, // <= ND_ASSIGN, // = ND_COND, // ?: ND_COMMA, // , ND_MEMBER, // . (struct member access) ND_ADDR, // unary & ND_DEREF, // unary * ND_NOT, // ! ND_BITNOT, // ~ ND_LOGAND, // && ND_LOGOR, // || ND_RETURN, // "return" ND_IF, // "if" ND_FOR, // "for" or "while" ND_DO, // "do" ND_SWITCH, // "switch" ND_CASE, // "case" ND_BLOCK, // { ... } ND_GOTO, // "goto" ND_GOTO_EXPR, // "goto" labels-as-values ND_LABEL, // Labeled statement ND_LABEL_VAL, // [GNU] Labels-as-values ND_FUNCALL, // Function call ND_EXPR_STMT, // Expression statement ND_STMT_EXPR, // Statement expression ND_VAR, // Variable ND_VLA_PTR, // VLA designator ND_NUM, // Integer ND_CAST, // Type cast ND_MEMZERO, // Zero-clear a stack variable ND_ASM, // "asm" ND_CAS, // Atomic compare-and-swap ND_EXCH, // Atomic exchange ND_FPCLASSIFY, // floating point classify } NodeKind; struct Node { NodeKind kind; // Node kind Node *next; // Next node Type *ty; // Type, e.g. int or pointer to int Token *tok; // Representative token Node *lhs; // Left-hand side Node *rhs; // Right-hand side // "if" or "for" statement Node *cond; Node *then; Node *els; Node *init; Node *inc; // Block or statement expression Node *body; // Function call Type *func_ty; Node *args; Obj *ret_buffer; bool pass_by_stack; bool realign_stack; // Switch Node *case_next; Node *default_case; // Goto or labeled statement, or labels-as-values char *label; char *unique_label; Node *goto_next; // "break" and "continue" labels char *brk_label; char *cont_label; // Case long begin; long end; // Struct member access Member *member; // Assembly Asm *azm; // Atomic compare-and-swap Node *cas_addr; Node *cas_old; Node *cas_new; // Atomic op= operators Obj *atomic_addr; Node *atomic_expr; // Variable Obj *var; // Arithmetic Node *overflow; // Numeric literal int64_t val; long double fval; FpClassify *fpc; }; Node *expr(Token **, Token *); Node *new_cast(Node *, Type *); Node *new_node(NodeKind, Token *); Obj *parse(Token *); bool is_const_expr(Node *); char *ConsumeStringLiteral(Token **, Token *); int64_t const_expr(Token **, Token *); int64_t eval(Node *); int64_t eval2(Node *, char ***); // // debug.c // void print_ast(FILE *, Obj *); // // type.c // typedef enum { TY_VOID, TY_BOOL, TY_CHAR, TY_SHORT, TY_INT, TY_LONG, TY_INT128, TY_FLOAT, TY_DOUBLE, TY_LDOUBLE, TY_ENUM, TY_PTR, TY_FUNC, TY_ARRAY, TY_VLA, // variable-length array TY_STRUCT, TY_UNION, } TypeKind; struct Type { TypeKind kind; int size; // sizeof() value int align; // alignment bool is_unsigned; // unsigned or signed bool is_atomic; // true if _Atomic Type *origin; // for type compatibility check // Pointer-to or array-of type. We intentionally use the same member // to represent pointer/array duality in C. // // In many contexts in which a pointer is expected, we examine this // member instead of "kind" member to determine whether a type is a // pointer or not. That means in many contexts "array of T" is // naturally handled as if it were "pointer to T", as required by // the C spec. Type *base; // Declaration Token *name; Token *name_pos; // Array int array_len; int vector_size; // Variable-length array Node *vla_len; // # of elements Obj *vla_size; // sizeof() value // Struct Member *members; bool is_flexible; bool is_packed; bool is_aligned; // Function type Type *return_ty; Type *params; bool is_variadic; Type *next; }; // Struct member struct Member { Member *next; Type *ty; Token *tok; // for error message Token *name; int idx; int align; int offset; // Bitfield bool is_bitfield; int bit_offset; int bit_width; }; extern Type ty_void[1]; extern Type ty_bool[1]; extern Type ty_char[1]; extern Type ty_short[1]; extern Type ty_int[1]; extern Type ty_long[1]; extern Type ty_int128[1]; extern Type ty_uchar[1]; extern Type ty_ushort[1]; extern Type ty_uint[1]; extern Type ty_ulong[1]; extern Type ty_uint128[1]; extern Type ty_float[1]; extern Type ty_double[1]; extern Type ty_ldouble[1]; bool is_integer(Type *); bool is_flonum(Type *); bool is_numeric(Type *); bool is_compatible(Type *, Type *); Type *copy_type(Type *); Type *pointer_to(Type *); Type *func_type(Type *); Type *array_of(Type *, int); Type *vla_of(Type *, Node *); Type *enum_type(void); Type *struct_type(void); void add_type(Node *); // // cast.c // void gen_cast(Type *, Type *); // // codegen.c // extern int depth; extern FILE *output_stream; int align_to(int, int); int count(void); void cmp_zero(Type *); void codegen(Obj *, FILE *); void gen_stmt(Node *); void println(char *, ...) __attribute__((__format__(__printf__, 1, 2))); // // unicode.c // int encode_utf8(char *, uint32_t); uint32_t decode_utf8(char **, char *); bool is_ident1(uint32_t); bool is_ident2(uint32_t); int display_width(char *, int); // // hashmap.c // typedef struct { char *key; int keylen; void *val; } HashEntry; typedef struct { HashEntry *buckets; int capacity; int used; } HashMap; void *hashmap_get(HashMap *, char *); void *hashmap_get2(HashMap *, char *, int); void hashmap_put(HashMap *, char *, void *); void hashmap_put2(HashMap *, char *, int, void *); void hashmap_delete(HashMap *, char *); void hashmap_delete2(HashMap *, char *, int); void hashmap_test(void); // // chibicc.c // extern StringArray include_paths; extern bool opt_common; extern bool opt_data_sections; extern bool opt_fentry; extern bool opt_function_sections; extern bool opt_no_builtin; extern bool opt_nop_mcount; extern bool opt_pg; extern bool opt_pic; extern bool opt_popcnt; extern bool opt_record_mcount; extern bool opt_sse3; extern bool opt_sse4; extern bool opt_verbose; extern char *base_file; int chibicc(int, char **); // // alloc.c // extern long alloc_node_count; extern long alloc_token_count; extern long alloc_obj_count; extern long alloc_type_count; Node *alloc_node(void); Token *alloc_token(void); Obj *alloc_obj(void); Type *alloc_type(void); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_ */