From 2bdbf387261285d07e4b62d1e23c9e43efb14604 Mon Sep 17 00:00:00 2001 From: Ákos Kőrösi Date: Tue, 19 May 2026 21:13:19 +0200 Subject: restructure dir, create makefile --- redes/lexparse.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ redes/syntax.h | 167 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 352 insertions(+) create mode 100644 redes/lexparse.c create mode 100644 redes/syntax.h (limited to 'redes') diff --git a/redes/lexparse.c b/redes/lexparse.c new file mode 100644 index 0000000..0ea86df --- /dev/null +++ b/redes/lexparse.c @@ -0,0 +1,185 @@ +#include +#include "syntax.h" +#include "utils.h" + +typedef struct { + Word word_germ; + String lit_germ; +} LexingBuffer; + +typedef struct { + TokenVec* token_pool; + TokenPtrVec* top_tokens; +} PseudoAst; + +static void consolidate_buffer(LexingBuffer* buf, PseudoAst ps_ast) { + 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) { + Token* tok_ptr = push_to_TokenVec(ps_ast.token_pool, (Token){ + .kind = TOK_WORD, + .as.word = buf->word_germ + }); + push_to_TokenPtrVec(ps_ast.top_tokens, tok_ptr); + } +} + + +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 = SPEC_PIPE}; + case '>': + next_ch = line[(*pos)+1]; + switch (next_ch) { + case '(': + return (MaybeSpecialToken){.some = false}; + case '>': + *pos += 2; + return (MaybeSpecialToken){.some = true, .value = SPEC_REDIR_W_APPEND}; + default: + (*pos)++; + return (MaybeSpecialToken){.some = true, .value = SPEC_REDIR_W_TRUNC}; + } + case '<': + next_ch = line[(*pos)+1]; + if (line[(*pos)+1] == '(') { + return (MaybeSpecialToken){.some = false}; + } else { + (*pos)++; + return (MaybeSpecialToken){.some = true, .value = SPEC_REDIR_R}; + } + default: + return (MaybeSpecialToken){.some = false}; + } +} + +static void lex_level(char* line, size_t* pos, char until, PseudoAst ps_ast) { + LexingBuffer buf = {.word_germ = make_Word(256), .lit_germ = make_String(256)}; + while (line[*pos] != until) { + if (line[*pos] == ' ') { + consolidate_buffer(&buf, ps_ast); + while (line[*pos] == ' ') (*pos)++; + continue; + } + MaybeSpecialToken m_spec = recognize_spec_token(line, pos); + if (m_spec.some) { + Token* tok_ptr = push_to_TokenVec(ps_ast.token_pool, (Token){ + .kind = TOK_SPEC, + .as.spec = m_spec.value + }); + push_to_TokenPtrVec(ps_ast.top_tokens, tok_ptr); + 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; + consolidate_buffer(&buf, ps_ast); + TokenPtrVec procsub_toks = make_TokenPtrVec(256); + lex_level(line, pos, ')', (PseudoAst){ + .token_pool = ps_ast.token_pool, + .top_tokens = &procsub_toks + }); + (*pos)++; // consume ')' + Token* tok_ptr = push_to_TokenVec(ps_ast.token_pool, (Token){ + .kind = TOK_SUB_IN, + .as.procsub_toks = procsub_toks, + }); + push_to_TokenPtrVec(ps_ast.top_tokens, tok_ptr); + } else if (line[*pos] == '>' && line[(*pos)+1] == '(') { + *pos += 2; + consolidate_buffer(&buf, ps_ast); + TokenPtrVec procsub_toks = make_TokenPtrVec(256); + lex_level(line, pos, ')', (PseudoAst){ + .token_pool = ps_ast.token_pool, + .top_tokens = &procsub_toks + }); + (*pos)++; // consume ')' + Token* tok_ptr = push_to_TokenVec(ps_ast.token_pool, (Token){ + .kind = TOK_SUB_OUT, + .as.procsub_toks = procsub_toks, + }); + push_to_TokenPtrVec(ps_ast.top_tokens, tok_ptr); + } + } +} + +Ast lex(char* input) { + size_t line_pos = 0; + TokenVec token_pool = make_TokenVec(256); + TokenPtrVec top_tokens = make_TokenPtrVec(256); + lex_level(input, &line_pos, '\0', (PseudoAst){ + .token_pool = &token_pool, + .top_tokens = &top_tokens + }); + return (Ast){.token_pool = token_pool, .top_tokens = top_tokens}; +} diff --git a/redes/syntax.h b/redes/syntax.h new file mode 100644 index 0000000..8404d15 --- /dev/null +++ b/redes/syntax.h @@ -0,0 +1,167 @@ +# pragma once + +#include "utils.h" + + +// Stage 1 + +typedef enum { + PLUS, + MINUS, + MULT, +DIV, +} BinOp; + +typedef enum { + ARITHM_INT_LIT, + ARITHM_BINOP, +} ArithmNodeKind; + +typedef struct ArithmNode ArithmNode; +struct ArithmNode { + ArithmNodeKind kind; + union { + int lit_val; + IntVec open_fds; + struct { + BinOp op; + ArithmNode* left; + ArithmNode* right; + } binop; + } as; +}; +DECLARE_VEC(ArithmNode, ArithmNodeVec) + + +typedef struct { + ArithmNodeVec nodes; + ArithmNode* root; +} ArithmAst; + + +typedef enum { + UN_Q, + SINGLE_Q, + DOUBLE_Q, +} QuotationMode; + +typedef enum { + CHUNK_LIT, + CHUNK_VAR, + CHUNK_CMDSUB, + CHUNK_ARITHM, +} ChunkKind; + +typedef struct { + QuotationMode qmode; + ChunkKind kind; + union { + char* lit_str; + char* varname; + ArithmAst arithm_expr; + // TODO: CHUNK_CMDSUB + } as; +} Chunk; + +DECLARE_VEC(Chunk, Word) + + +typedef enum { + TOK_WORD, + TOK_SPEC, + TOK_SUB_IN, + TOK_SUB_OUT, +} TokenKind; + +typedef enum { + SPEC_PIPE, + SPEC_REDIR_W_TRUNC, + SPEC_REDIR_W_APPEND, + SPEC_REDIR_R, + SPEC_EOL, +} SpecialToken; + +typedef struct Token Token; +DECLARE_VEC(Token*, TokenPtrVec) + +struct Token { + TokenKind kind; + union { + Word word; + SpecialToken spec; + TokenPtrVec procsub_toks; + } as; +}; + +DECLARE_VEC(Token, TokenVec) + +typedef struct { + TokenVec token_pool; + TokenPtrVec top_tokens; +} Ast; + + + +// Stage 2 + + +typedef enum { + REDIR_FILE_IN, + REDIR_FILE_OUT, + REDIR_FDS, +} RedirectKind; + +typedef struct { + RedirectKind kind; + union { + char* filename; + struct{int from; int to;} fds; + } as; +} Redirect; + +DECLARE_VEC(Redirect, RedirectVec) + +typedef struct { + char** args; + RedirectVec redirects; +} SimpleCommand; + +DECLARE_VEC(SimpleCommand, SimpleCommandVec) +DECLARE_VEC(SimpleCommand*, SimpleCommandPtrVec) + + +typedef enum { + CONN_PIPE, + CONN_EOL, +} Connector; + +typedef struct { + SimpleCommand* cmd; + SimpleCommandPtrVec deps; + Connector conn; +} PlCommand; + +DECLARE_VEC(PlCommand, PlCommandVec) + +typedef struct { + SimpleCommandVec commands; + PlCommandVec pipeline; +} ExecTree; + + + +// Stage 3 + +typedef struct { + int redirected; + int to; +} FdRedirect; + +DECLARE_VEC(FdRedirect, FdRedirectVec) + +typedef struct { + char** args; + FdRedirectVec redirects; + int stdin_fd, stdout_fd; + IntVec open_fds; +} ExecutableCommand; -- cgit v1.2.3