From fc27548c447ed9bcd07493983431e0a6e72c7cef Mon Sep 17 00:00:00 2001 From: Ákos Kőrösi Date: Thu, 21 May 2026 12:44:01 +0200 Subject: restructure dir --- src/preproc.c | 393 ++++++++++++++++------------------------------------------ 1 file changed, 105 insertions(+), 288 deletions(-) (limited to 'src/preproc.c') diff --git a/src/preproc.c b/src/preproc.c index 4cd1c5b..63e618f 100644 --- a/src/preproc.c +++ b/src/preproc.c @@ -1,318 +1,135 @@ -#include -#include -#include -#include -#include +#include #include +#include "syntax.h" -#include "preproc.h" -#include "utils.h" - - -// Lexing - -typedef struct { - char* str; - size_t pos; -} RawLine; - - -String collect_identifier(RawLine* line) { - String id_buf = make_String(256); - while (line->str[line->pos] == '_' || isalnum(line->str[line->pos])) { - push_to_String(&id_buf, line->str[line->pos++]); - } - return id_buf; -} - - - -TokenPtrVec lex_level(RawLine* line, char until, PreprocArena* arena); - - -void expect_char(RawLine* line, char expected) { - if (line->str[line->pos] != expected) { - exit(45); // TODO: nicer handling - } - line->pos++; -} - - -/* -MaybeChunk lex_expansion_chunk(RawLine* line, RegionVec* reg_arena, QuotationMode qmode) { - line->pos++; // Consume $ - if (line->str[line->pos] == '(') { - line->pos++; - if (line->str[line->pos] == '(') { - exit(1); - // TODO: this (and potentially the other parsers must be custom, we need to recognize arithm-internal parens from the terminating `))` ) - - - TokenVec inner_toks = lex_level(line, ')', reg_arena); - expect_char(line, ')'); - expect_char(line, ')'); - Region* reg_ptr = push_to_RegionVec( - reg_arena, - (Region){.mode = ARITHM, .tokens = inner_toks} - ); - return (MaybeChunk){ - .some = true, - .value = (Chunk){ - .qmode = qmode, - .kind = REGION_EXP, - .as.reg_ptr = reg_ptr - }, - }; - } else { - TokenVec inner_toks = lex_level(line, ')', reg_arena); - expect_char(line, ')'); - Region* reg_ptr = push_to_RegionVec( - reg_arena, - (Region){.mode = CMDS, .tokens = inner_toks} - ); - return (MaybeChunk) { - .some = true, - .value = (Chunk){ - .qmode = qmode, - .kind = REGION_EXP, - .as.reg_ptr = reg_ptr, - } - }; - } - } else { - String id_name = collect_identifier(line); - if (id_name.count > 0) { - return (MaybeChunk){ - .some = true, - .value = (Chunk){ - .qmode = qmode, - .kind = VAR_EXP, - .as.varname = inner(&id_name), - } - }; - } - } - return (MaybeChunk){.some = false}; -} -*/ - - -void lex_double_quoted_section(RawLine* line, Word* coll, PreprocArena* arena) { - line->pos++; - String accum = make_String(256); - while (line->str[line->pos] != '\"') { - if (line->str[line->pos] == '\0') exit(43); - - MaybeChunk exp_chunk = {.some = false}; - - if (line->str[line->pos] == '$') { - exit(1); - /* - exp_chunk = lex_expansion_chunk(line, reg_arena, DOUBLE_Q); - if (!exp_chunk.some) { - push_to_String(&accum, '$'); - } - */ +void split_str_on_space(char* str, StrVec* result) { + String buf = make_String(256); + for (int pos = 0; str[pos] != '\0'; pos++) { + if (str[pos] == ' ') { + push_to_StrVec(result, inner(&buf)); + buf = make_String(256); } else { - push_to_String(&accum, line->str[line->pos++]); - } - // TODO: other special cases beyond $ - - if (exp_chunk.some) { - if (accum.count > 0) { - Chunk accum_chunk = {.qmode = DOUBLE_Q, .kind = LITERAL, .as.literal_str = inner(&accum)}; - Chunk* accum_ptr = push_to_ChunkVec(&arena->chunks, accum_chunk); - push_to_Word(coll, accum_ptr); - accum = make_String(256); - } - Chunk* exp_ptr = push_to_ChunkVec(&arena->chunks, exp_chunk.value); - push_to_Word(coll, exp_ptr); - exp_chunk.some = false; + push_to_String(&buf, str[pos]); } } - line->pos++; - if (accum.count > 0) { - Chunk accum_chunk = {.qmode = DOUBLE_Q, .kind = LITERAL, .as.literal_str = inner(&accum)}; - Chunk* accum_ptr = push_to_ChunkVec(&arena->chunks, accum_chunk); - push_to_Word(coll, accum_ptr); - accum = make_String(256); - } -} - -Chunk next_word_unquoted(RawLine* line, RegionVec* reg_arena) { - String buf = make_String(256); - for (char c; (c=line->str[line->pos], c != '$' && c != '\0' && c != ' '); line->pos++) { - push_to_String(&buf, c); + if (buf.count > 0) { + char* buf_str = inner(&buf); + push_to_StrVec(result, buf_str); } - return (Chunk){.qmode = UN_Q, .kind = LITERAL, .as.literal_str = inner(&buf)}; } - -Chunk collect_single_quoted_section(RawLine* line) { - line->pos++; // Consume quote mark - String chunk_str = make_String(256); - while (line->str[line->pos] != '\'') { - if (line->str[line->pos] == '\0') exit(44); - push_to_String(&chunk_str, line->str[line->pos++]); +StrVec process_word(Word word) { + StrVec result = make_StrVec(256); + for (int i = 0; i < word.count; i++) { + Chunk chunk = *get_from_Word(&word, i); + switch (chunk.qmode) { + case SINGLE_Q: + push_to_StrVec(&result, chunk.as.lit_str); + break; + case DOUBLE_Q: + // TODO + exit(67); + break; + case UN_Q: + // TODO: this only does literals, implement the rest + split_str_on_space(chunk.as.lit_str, &result); + break; + } } - line->pos++; // Consume closing quote - return (Chunk){ - .qmode = SINGLE_Q, - .kind = LITERAL, - .as.literal_str = inner(&chunk_str), - }; + return result; } typedef struct { - Word word_germ; - String unq_liter_germ; -} LexState; - - -void close_word_and_lit_germs(LexState* state, TokenPtrVec* toks, PreprocArena* arena) { - if (state->unq_liter_germ.count > 0) { - Chunk chu = { - .qmode = UN_Q, - .kind = LITERAL, - .as.literal_str = inner(&state->unq_liter_germ) - }; - Chunk* chu_ptr = push_to_ChunkVec(&arena->chunks, chu); - push_to_Word(&state->word_germ, chu_ptr); - state->unq_liter_germ = make_String(256); - } - if (state->word_germ.count > 0) { - Token tok = {.kind = TOK_WORD, .as.word = state->word_germ}; - Token* tok_ptr = push_to_TokenVec(&arena->tokens, tok); - push_to_TokenPtrVec(toks, tok_ptr); - state->word_germ = make_Word(256); - } -} + TokenKind kind; + union { + char* word; + SpecialToken spec; + } as; +} ExpandedToken; -TokenPtrVec lex_level(RawLine* line, char until, PreprocArena* arena) { +DECLARE_VEC(ExpandedToken, ExpandedTokenVec) - TokenPtrVec line_toks = make_TokenPtrVec(256); - LexState state = { - .word_germ = make_Word(256), - .unq_liter_germ = make_String(256) - }; +Pipeline* process_token_sequence(TokenVec tokens, PipelineVec* pl_pool) { - while (line->str[line->pos] != until) { + ExpandedTokenVec exp_tokens = make_ExpandedTokenVec(256); - if (line->str[line->pos] == ' ') { - close_word_and_lit_germs(&state, &line_toks, arena); - while (line->str[line->pos] == ' ') line->pos++; - continue; + for (int m = 0; m < tokens.count; m++) { + Token tok = *get_from_TokenVec(&tokens, m); + StrVec strs; + switch (tok.kind) { + case TOK_SPEC: + push_to_ExpandedTokenVec(&exp_tokens, (ExpandedToken){.kind = TOK_SPEC, .as.spec = tok.as.spec}); + break; + case TOK_WORD: + strs = process_word(tok.as.word); + for (int n = 0; n < strs.count; n++) { + push_to_ExpandedTokenVec(&exp_tokens, (ExpandedToken){.kind = TOK_WORD, .as.word = *get_from_StrVec(&strs, n)}); + } } + } - Token* tok_ptr; + Pipeline pl = make_Pipeline(256); + size_t tok_pos = 0; - switch (line->str[line->pos]) { - case '\'': - push_to_Word(&state.word_germ, push_to_ChunkVec(&arena->chunks, collect_single_quoted_section(line))); - break; - case '\"': - lex_double_quoted_section(line, &state.word_germ, arena); - break; - case '|': - line->pos++; - close_word_and_lit_germs(&state, &line_toks, arena); - tok_ptr = push_to_TokenVec(&arena->tokens, (Token){.kind = TOK_SPECIAL, .as.spec = PIPE}); - push_to_TokenPtrVec(&line_toks, tok_ptr); - break; - case '$': - exit(1); - /* - line->pos++; - MaybeChunk mchunk = lex_expansion_chunk(line, reg_arena, UN_Q); - if (mchunk.some) { - push_to_Word(&state.word_germ, mchunk.value); - } else { - push_to_String(&state.unq_liter_germ, '$'); - } - */ - break; - case '>': - close_word_and_lit_germs(&state, &line_toks, arena); - line->pos++; + PlCommand curr_cmd = {.args = make_ArgVec(256), .redirects = make_RedirectVec(256), .conn = CONN_EOL}; - switch (line->str[line->pos]) { - case '(': - line->pos++; - TokenPtrVec sub_regtoks = lex_level(line, ')', arena); - line->pos++; - Region subreg = {.mode = CMDS, .tokens = sub_regtoks}; - Region* subreg_ptr = push_to_RegionVec(&arena->regions, subreg); - Token tok = {.kind = TOK_PROCSUB_OUT, .as.procsub_region = subreg_ptr}; - tok_ptr = push_to_TokenVec(&arena->tokens, tok); - push_to_TokenPtrVec(&line_toks, tok_ptr); - break; - case '>': - line->pos++; - tok_ptr = push_to_TokenVec(&arena->tokens, (Token){.kind = TOK_SPECIAL, .as.spec = WRITE_REDIR_APPEND}); - push_to_TokenPtrVec(&line_toks, tok_ptr); + PlCommand* root_pl; + for (int i = 0; i < exp_tokens.count; i++) { + ExpandedToken curr_tok = *get_from_ExpandedTokenVec(&exp_tokens, i); + ExpandedToken next_tok; + Redirect rd; + switch (curr_tok.kind) { + case TOK_WORD: + push_to_ArgVec(&curr_cmd.args, (Arg){.kind = ARG_LIT, .as.lit_str = curr_tok.as.word}); + break; + case TOK_SPEC: + switch (curr_tok.as.spec.kind) { + case SPEC_OP: + switch (curr_tok.as.spec.as.op) { + case OP_PIPE: + curr_cmd.conn = CONN_PIPE; + push_to_Pipeline(&pl, curr_cmd); + curr_cmd = (PlCommand){.args = make_ArgVec(256), .redirects = make_RedirectVec(256), .conn = CONN_EOL}; + break; + case OP_EOL: + push_to_Pipeline(&pl, curr_cmd); + break; + case OP_REDIR_R: + next_tok = *get_from_ExpandedTokenVec(&exp_tokens, ++i); + assert(next_tok.kind == TOK_WORD); + rd = (Redirect){.kind = REDIR_READ, .as.filename = next_tok.as.word}; + push_to_RedirectVec(&curr_cmd.redirects, rd); + break; + case OP_REDIR_W_APPEND: + next_tok = *get_from_ExpandedTokenVec(&exp_tokens, ++i); + assert(next_tok.kind == TOK_WORD); + rd = (Redirect){.kind = REDIR_WRITE_APPEND, .as.filename = next_tok.as.word}; + push_to_RedirectVec(&curr_cmd.redirects, rd); + break; + case OP_REDIR_W_TRUNC: + next_tok = *get_from_ExpandedTokenVec(&exp_tokens, ++i); + assert(next_tok.kind == TOK_WORD); + rd = (Redirect){.kind = REDIR_WRITE_TRUNC, .as.filename = next_tok.as.word}; + push_to_RedirectVec(&curr_cmd.redirects, rd); + break; + default: + exit(63); + } break; default: - tok_ptr = push_to_TokenVec(&arena->tokens, (Token){.kind = TOK_SPECIAL, .as.spec = WRITE_REDIR_TRUNC}); - push_to_TokenPtrVec(&line_toks, tok_ptr); + exit(62); } - break; - case '<': - close_word_and_lit_germs(&state, &line_toks, arena); - line->pos++; - if (line->str[line->pos] == '(') { - line->pos++; - TokenPtrVec sub_regtoks = lex_level(line, ')', arena); - line->pos++; - Region subreg = {.mode = CMDS, .tokens = sub_regtoks}; - Region* reg_ptr = push_to_RegionVec(&arena->regions, subreg); - Token reg_tok = {.kind = TOK_PROCSUB_IN, .as.procsub_region = reg_ptr}; - Token* reg_tok_ptr = push_to_TokenVec(&arena->tokens, reg_tok); - push_to_TokenPtrVec(&line_toks, reg_tok_ptr); - } else { - Token* redir_ptr = push_to_TokenVec(&arena->tokens, (Token){.kind = TOK_SPECIAL, .as.spec = READ_REDIR}); - push_to_TokenPtrVec(&line_toks, redir_ptr); - } - break; - default: - push_to_String(&state.unq_liter_germ, line->str[line->pos++]); } - } - // TODO: handle until char _and_ EOL - close_word_and_lit_germs(&state, &line_toks, arena); - return line_toks; -} - - -TokenPtrVec lex(char* input, PreprocArena* arena) { - RawLine line = {.str = input, .pos = 0}; - TokenPtrVec toks = lex_level(&line, '\0', arena); - Token* eol_ptr = push_to_TokenVec(&arena->tokens, (Token){.kind = TOK_SPECIAL, .as.spec = EOL}); - push_to_TokenPtrVec(&toks, eol_ptr); - return toks; + } + return push_to_PipelineVec(pl_pool, pl); } - - -// Parsing - -Pipeline parse_tokstream(Token* toks) { - size_t tok_pos = 0; - Pipeline result = make_Pipeline(256); - TokenVec tok_buf = make_TokenVec(256); - while (true) { - Token curr_tok = toks[tok_pos++]; - if (curr_tok.kind == TOK_SPECIAL && curr_tok.as.spec == PIPE) { - push_to_Pipeline(&result, (PipelineElement){.cmd_toks = tok_buf, .conn = CONN_PIPE}); - tok_buf = make_TokenVec(256); - } else if (curr_tok.kind == TOK_SPECIAL && curr_tok.as.spec == EOL) { - push_to_Pipeline(&result, (PipelineElement){.cmd_toks = tok_buf, .conn = CONN_EOL}); - break; - } else { - push_to_TokenVec(&tok_buf, curr_tok); - } - } - return result; +PipelineTree process_ast(Ast ast) { + PipelineVec pls = make_PipelineVec(256); + TokenVec root_toks = *ast.root; + Pipeline* root_pl = process_token_sequence(root_toks, &pls); + return (PipelineTree){.pl_pool = pls, root_pl}; } -- cgit v1.2.3