cosmopolitan/third_party/chibicc/chibicc.h

589 lines
13 KiB
C

#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_ */