#include #include #include #include #include #include #include "lex.h" #include "typeutils.h" String collect_identifier(char* input, size_t* pos) { String id_buf = make_String(256); while (input[*pos] == '_' || isalnum(input[*pos])) { push_to_String(&id_buf, input[(*pos)++]); } return id_buf; } String collect_single_quoted_section(char* input, size_t* pos) { (*pos)++; // Consume quote mark String chunk_str = make_String(256); while (input[*pos] != '\'') { if (input[*pos] == '\0') exit(42); push_to_String(&chunk_str, input[(*pos)++]); } (*pos)++; // Consume closing quote return chunk_str; } TokenVec lex_region(char* input, size_t* pos, char until); void expect_char(char* input, size_t* pos, char expected) { if (input[*pos] != expected) exit(42); // TODO: nicer handling (*pos)++; } void lex_double_quoted_section(char* input, size_t* pos, ChunkVec* coll, ExpansionRegionVec* reg_arena) { (*pos)++; String accum = make_String(256); while (input[*pos] != '\"') { if (input[*pos] == '\0') exit(42); MaybeChunk exp_chunk = {.some = false}; if (input[*pos] == '$') { (*pos)++; if (input[*pos] == '(') { if (input[*pos] == '(') { TokenVec inner_toks = lex_region(input, pos, ')'); expect_char(input, pos, ')'); expect_char(input, pos, ')'); push_to_ExpansionRegionVec( reg_arena, (ExpansionRegion){.mode = ARITHM, .tokens = inner_toks} ); ExpansionRegion* reg_ptr = ®_arena->items[reg_arena->count]; // TODO: maybe have push() return a pointer [in the macro] exp_chunk = (MaybeChunk){ .some = true, .value = (Chunk){ .qmode = DOUBLE_Q, .kind = REGION_EXP, .as.reg_ptr = reg_ptr }, }; } else { TokenVec inner_toks = lex_region(input, pos, ')'); expect_char(input, pos, ')'); push_to_ExpansionRegionVec( reg_arena, (ExpansionRegion){.mode = CMD_SUB, .tokens = inner_toks} ); ExpansionRegion* reg_ptr = ®_arena->items[reg_arena->count]; exp_chunk = (MaybeChunk){ .some = true, .value = (Chunk){ .qmode = DOUBLE_Q, .kind = REGION_EXP, .as.reg_ptr = reg_ptr, } }; } } else { String id_name = collect_identifier(input, pos); if (id_name.count > 0) { exp_chunk = (MaybeChunk){ .some = true, .value = (Chunk){ .qmode = DOUBLE_Q, .kind = VAR_EXP, .as.varname = inner(id_name), } }; } else { push_to_String(&accum, '$'); } } } else { push_to_String(&accum, input[(*pos)++]); } // TODO: other special cases if (exp_chunk.some) { if (accum.count > 0) { push_to_ChunkVec(coll, (Chunk){ .qmode = DOUBLE_Q, .kind = LITERAL, .as.literal_str = inner(accum) }); accum = make_String(256); } push_to_ChunkVec(coll, exp_chunk.value); exp_chunk.some = false; } } if (accum.count > 0) { push_to_ChunkVec(coll, (Chunk){ .qmode = DOUBLE_Q, .kind = LITERAL, .as.literal_str = inner(accum) }); } } typedef struct { Region root_reg; RegionVec reg_arena; } LexResult; // TODO: maybe make an input+pos struct TokenVec lex_region(char* input, size_t* pos, char until) { TokenVec tokens = make_TokenVec(256); RegionVec reg_arena; while (input[*pos] != until) { // Getting a token if (input[*pos] == ' ') { (*pos)++; continue; } ChunkVec chunks = make_ChunkVec(256); switch (input[*pos]) { case '\'': String qstring = get_single_quoted_chunk(input, pos); push_to_ChunkVec(&chunks, (Chunk){.qmode=SINGLE_Q, .kind = LITERAL, .as.literal_str = qstring.items}); break; } } return tokens; } TokenVec lex(char* input) { size_t pos = 0; return lex_region(input, &pos, '\0'); }