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/lexparse.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 src/lexparse.c (limited to 'src/lexparse.c') diff --git a/src/lexparse.c b/src/lexparse.c new file mode 100644 index 0000000..3a55b33 --- /dev/null +++ b/src/lexparse.c @@ -0,0 +1,229 @@ +#include +#include "syntax.h" +#include "../src/utils.h" + +typedef struct { + Word word_germ; + String lit_germ; +} LexingBuffer; + +typedef struct { + TokenVec* token_pool; + TokenPtrVec* top_tokens; +} PseudoAst; + +DECLARE_MAYBE(Token, MaybeToken) + +MaybeToken consolidate_buffer(LexingBuffer* buf) { + if (buf->lit_germ.count > 0) { + push_to_Word(&buf->word_germ, (Chunk){ + .qmode = UN_Q, + .kind = CHUNK_LIT, + .as.lit_str = inner(&buf->lit_germ) + }); + buf->lit_germ = make_String(256); + } + if (buf->word_germ.count > 0) { + Word word_germ = buf->word_germ; + buf->word_germ = make_Word(256); + return (MaybeToken){ + .some = true, + .value = (Token){ + .kind = TOK_WORD, + .as.word = word_germ + } + }; + } + return (MaybeToken){.some = false}; +} + + +static Chunk collect_un_q_literal(char* line, size_t* pos) { + String buf = make_String(256); + size_t i; + for (i = *pos; line[*pos] != '$' && line[*pos] != '\0' && line[*pos] == ' '; i++) { + push_to_String(&buf, line[*pos]); + } + *pos = i; + return (Chunk){ + .qmode = UN_Q, + .kind = CHUNK_LIT, + .as.lit_str = inner(&buf), + }; +} + + +static Chunk collect_single_q_section(char* line, size_t* pos) { + (*pos)++; + String buf = make_String(256); + size_t i; + for (i = *pos; line[*pos] != '\'' && line[*pos] != '\0'; i++) { + push_to_String(&buf, line[*pos]); + } + if (line[i] == '\0') exit(44); + + *pos = ++i; + return (Chunk){ + .qmode = SINGLE_Q, + .kind = CHUNK_LIT, + .as.lit_str = inner(&buf) + }; +} + +static Chunk collect_double_q_section(char* line, size_t* pos) { + // TODO: add the extra double-q expansions + (*pos)++; + String buf = make_String(256); + size_t i; + for (i = *pos; line[*pos] != '\'' && line[*pos] != '\0'; i++) { + push_to_String(&buf, line[*pos]); + } + if (line[i] == '\0') exit(44); + + *pos = ++i; + return (Chunk){ + .qmode = DOUBLE_Q, + .kind = CHUNK_LIT, + .as.lit_str = inner(&buf) + }; +} + +DECLARE_MAYBE(SpecialToken, MaybeSpecialToken) + + +static MaybeSpecialToken recognize_spec_token(char* line, size_t* pos) { + // TODO: add more error guards for peekaheads + char next_ch; + + switch (line[*pos]) { + case '|': + (*pos)++; + return (MaybeSpecialToken){ + .some = true, + .value = (SpecialToken){ + .kind = SPEC_OP, + .as.op = OP_PIPE, + } + }; + case '>': + next_ch = line[(*pos)+1]; + switch (next_ch) { + case '(': + return (MaybeSpecialToken){.some = false}; + case '>': + *pos += 2; + return (MaybeSpecialToken){ + .some = true, + .value = (SpecialToken){ + .kind = SPEC_OP, + .as.op = OP_REDIR_W_APPEND, + } + }; + default: + (*pos)++; + return (MaybeSpecialToken){ + .some = true, + .value = (SpecialToken){ + .kind = SPEC_OP, + .as.op = OP_REDIR_W_TRUNC, + } + }; + } + case '<': + next_ch = line[(*pos)+1]; + if (line[(*pos)+1] == '(') { + return (MaybeSpecialToken){.some = false}; + } else { + (*pos)++; + return (MaybeSpecialToken){ + .some = true, + .value = (SpecialToken){ + .kind = SPEC_OP, + .as.op = OP_REDIR_R, + } + }; + } + default: + return (MaybeSpecialToken){.some = false}; + } +} + +TokenVec* lex_level(char* line, size_t* pos, char until, TokenVecVec* tok_seq_pool) { + TokenVec tokens = make_TokenVec(256); + LexingBuffer buf = {.word_germ = make_Word(256), .lit_germ = make_String(256)}; + while (line[*pos] != until) { + if (line[*pos] == ' ') { + MaybeToken m_tok = consolidate_buffer(&buf); + if (m_tok.some) { + push_to_TokenVec(&tokens, m_tok.value); + } + while (line[*pos] == ' ') (*pos)++; + continue; + } + MaybeSpecialToken m_spec = recognize_spec_token(line, pos); + if (m_spec.some) { + MaybeToken m_tok = consolidate_buffer(&buf); + if (m_tok.some) { + push_to_TokenVec(&tokens, m_tok.value); + } + push_to_TokenVec(&tokens, (Token){.kind = TOK_SPEC, .as.spec = m_spec.value}); + continue; + } + + if (line[*pos] == '\'') { + Chunk chunk = collect_single_q_section(line, pos); + push_to_Word(&buf.word_germ, chunk); + } else if (line[*pos] == '\"') { + Chunk chunk = collect_double_q_section(line, pos); + push_to_Word(&buf.word_germ, chunk); + } else if (line[*pos] == '<' && line[(*pos)+1] == '(') { + *pos += 2; + MaybeToken m_tok = consolidate_buffer(&buf); + if (m_tok.some) { + push_to_TokenVec(&tokens, m_tok.value); + } + TokenVec* sub_toks = lex_level(line, pos, ')', tok_seq_pool); + (*pos)++; + push_to_TokenVec(&tokens, (Token){ + .kind = TOK_SPEC, + .as.spec = (SpecialToken){ + .kind = SPEC_SUB_IN, + .as.proc_sub_region = sub_toks + } + }); + } else if (line[*pos] == '>' && line[(*pos)+1] == '(') { + *pos += 2; + MaybeToken m_tok = consolidate_buffer(&buf); + if (m_tok.some) { + push_to_TokenVec(&tokens, m_tok.value); + } + TokenVec* sub_toks = lex_level(line, pos, ')', tok_seq_pool); + (*pos)++; + push_to_TokenVec(&tokens, (Token){ + .kind = TOK_SPEC, + .as.spec = (SpecialToken){ + .kind = SPEC_SUB_OUT, + .as.proc_sub_region = sub_toks + } + }); + } else { + push_to_String(&buf.lit_germ, line[(*pos)++]); + } + } + MaybeToken m_last = consolidate_buffer(&buf); + if (m_last.some) { + push_to_TokenVec(&tokens, m_last.value); + } + + if (until == '\0') { + push_to_TokenVec(&tokens, (Token){.kind = TOK_SPEC, .as.spec = (SpecialToken){.kind = SPEC_OP, .as.op = OP_EOL}}); + } + return push_to_TokenVecVec(tok_seq_pool, tokens); +} + +Ast lex(char* input) { + size_t line_pos = 0; + TokenVecVec token_seqs = make_TokenVecVec(256); + TokenVec* root_ptr = lex_level(input, &line_pos, '\0', &token_seqs); + return (Ast){.region_pool = token_seqs, .root = root_ptr}; +} -- cgit v1.2.3