diff options
| author | Ákos Kőrösi <korakos99@gmail.com> | 2026-05-12 16:28:30 +0200 |
|---|---|---|
| committer | Ákos Kőrösi <korakos99@gmail.com> | 2026-05-12 16:28:30 +0200 |
| commit | 89625d33abbdb99659ad6d8fa3df0de0b7a72f10 (patch) | |
| tree | d26a70c2f342f1f2dcaf3c9847723cbbfba7be51 | |
| parent | 32babee5145bb0248566960a69b674484deb3f94 (diff) | |
fix bugs in lex/parse, add ugly print util
| -rw-r--r-- | lex.c | 14 | ||||
| -rw-r--r-- | main.c | 26 | ||||
| -rw-r--r-- | parse.c | 48 | ||||
| -rw-r--r-- | typeutils.h | 119 |
4 files changed, 134 insertions, 73 deletions
@@ -31,7 +31,6 @@ TokenVec lex_level(RawLine* line, char until, RegionVec* reg_arena); void expect_char(RawLine* line, char expected) { if (line->str[line->pos] != expected) { - printf("Expected %c, got %c.", expected, line->str[line->pos]); exit(45); // TODO: nicer handling } line->pos++; @@ -86,7 +85,7 @@ MaybeChunk lex_expansion_chunk(RawLine* line, RegionVec* reg_arena, QuotationMod .value = (Chunk){ .qmode = qmode, .kind = VAR_EXP, - .as.varname = inner(id_name), + .as.varname = inner(&id_name), } }; } @@ -118,7 +117,7 @@ void lex_double_quoted_section(RawLine* line, Word* coll, RegionVec* reg_arena) push_to_Word(coll, (Chunk){ .qmode = DOUBLE_Q, .kind = LITERAL, - .as.literal_str = inner(accum) + .as.literal_str = inner(&accum) }); accum = make_String(256); } @@ -131,7 +130,7 @@ void lex_double_quoted_section(RawLine* line, Word* coll, RegionVec* reg_arena) push_to_Word(coll, (Chunk){ .qmode = DOUBLE_Q, .kind = LITERAL, - .as.literal_str = inner(accum) + .as.literal_str = inner(&accum) }); } } @@ -142,7 +141,7 @@ Chunk next_word_unquoted(RawLine* line, RegionVec* reg_arena) { for (char c; (c=line->str[line->pos], c != '$' && c != '\0' && c != ' '); line->pos++) { push_to_String(&buf, c); } - return (Chunk){.qmode = UN_Q, .kind = LITERAL, .as.literal_str = inner(buf)}; + return (Chunk){.qmode = UN_Q, .kind = LITERAL, .as.literal_str = inner(&buf)}; } @@ -157,7 +156,7 @@ Chunk collect_single_quoted_section(RawLine* line) { return (Chunk){ .qmode = SINGLE_Q, .kind = LITERAL, - .as.literal_str = inner(chunk_str), + .as.literal_str = inner(&chunk_str), }; } @@ -176,7 +175,7 @@ void close_literal_germ(LexState* state) { (Chunk){ .qmode = UN_Q, .kind = LITERAL, - .as.literal_str = inner(state->unq_liter_germ) + .as.literal_str = inner(&state->unq_liter_germ) } ); state->unq_liter_germ = make_String(256); @@ -201,6 +200,7 @@ TokenVec lex_level(RawLine* line, char until, RegionVec* reg_arena) { while (line->str[line->pos] != until) { + if (line->str[line->pos] == ' ') { close_word_and_lit_germs(&state); while (line->str[line->pos] == ' ') line->pos++; @@ -6,6 +6,28 @@ #include "lex.h" #include "parse.h" +void uglyprint_pl(Pipeline pl) { + for (int i = 0; i < pl.count; i++) { + printf("%d\n"); + TokenVec toks = (*get_from_Pipeline(&pl, i)).cmd.args; + for (int j = 0; j < toks.count; j++) { + Token tok = *get_from_TokenVec(&toks, j); + if (tok.kind != TOK_WORD) { + printf(" [NON-WORD] "); + continue; + } + Word word = tok.as.word; + for (int k = 0; k < word.count; k++) { + Chunk chunk = *get_from_Word(&word, k); + if (chunk.kind == LITERAL) { + printf("%s", chunk.as.literal_str); + } + } + } + } +} + + int main() { char* line; while (1) { @@ -14,11 +36,9 @@ int main() { if (strcmp(line, "exit") == 0) exit(0); LexResult res = lex(line); Pipeline pl = parse_tokstream(res.top_tokens); - printf("%s \n", line); + uglyprint_pl(pl); } - free(line); - } @@ -8,18 +8,21 @@ DECLARE_VEC(char*, StrVec) typedef struct { - Token* ptr; - size_t len; + TokenVec vec; size_t pos; } TokStream; Connector parse_connector(TokStream* toks) { - Token tok = toks->ptr[toks->pos]; + Token tok = *get_from_TokenVec(&toks->vec, toks->pos); if (tok.kind != TOK_SPECIAL) exit(67); switch (tok.as.spec) { - case PIPE: return CONN_PIPE; - case EOL: return CONN_EOL; + case PIPE: + toks->pos++; + return CONN_PIPE; + case EOL: + toks->pos++; + return CONN_EOL; default: exit(76); } } @@ -28,32 +31,31 @@ Connector parse_connector(TokStream* toks) { Command parse_command(TokStream* toks) { TokenVec args = make_TokenVec(256); RedirectVec redirects = make_RedirectVec(256); - for ( - Token curr_tok; - (curr_tok = toks->ptr[toks->pos], !(curr_tok.kind == TOK_SPECIAL && (curr_tok.as.spec == PIPE || curr_tok.as.spec == EOL))); - toks->pos++ - ) { + while (true) { + Token curr_tok = *get_from_TokenVec(&toks->vec, toks->pos); + if (curr_tok.kind == TOK_SPECIAL &&(curr_tok.as.spec == PIPE || curr_tok.as.spec == EOL)) { + break; + } + switch (curr_tok.kind) { case TOK_SPECIAL: - Token tok; + toks->pos++; + Token name_tok = *get_from_TokenVec(&toks->vec, toks->pos); switch (curr_tok.as.spec) { case WRITE_REDIR_TRUNC: toks->pos++; - tok = toks->ptr[toks->pos]; - if(tok.kind != TOK_WORD) exit(1); - push_to_RedirectVec(&redirects, (Redirect){.kind = STDOUT_REDIR_TRUNC, .as.std_redir_filename = tok.as.word}); + if(name_tok.kind != TOK_WORD) exit(1); + push_to_RedirectVec(&redirects, (Redirect){.kind = STDOUT_REDIR_TRUNC, .as.std_redir_filename = name_tok.as.word}); break; case WRITE_REDIR_APPEND: toks->pos++; - tok = toks->ptr[toks->pos]; - if(tok.kind != TOK_WORD) exit(1); - push_to_RedirectVec(&redirects, (Redirect){.kind = STDOUT_REDIR_APPEND, .as.std_redir_filename = tok.as.word}); + if(name_tok.kind != TOK_WORD) exit(1); + push_to_RedirectVec(&redirects, (Redirect){.kind = STDOUT_REDIR_APPEND, .as.std_redir_filename = name_tok.as.word}); break; case READ_REDIR: toks->pos++; - tok = toks->ptr[toks->pos]; - if(tok.kind != TOK_WORD) exit(1); - push_to_RedirectVec(&redirects, (Redirect){.kind = STDOUT_REDIR_APPEND, .as.std_redir_filename = tok.as.word}); + if(name_tok.kind != TOK_WORD) exit(1); + push_to_RedirectVec(&redirects, (Redirect){.kind = STDOUT_REDIR_APPEND, .as.std_redir_filename = name_tok.as.word}); break; default: exit(69); @@ -62,13 +64,14 @@ Command parse_command(TokStream* toks) { default: push_to_TokenVec(&args, curr_tok); } + toks->pos++; } return (Command){.args = args, .redirects = redirects}; } -Pipeline parse_tokstream(TokenVec toks) { - TokStream tokstream = {.ptr = toks.items, .len = toks.count, .pos = 0}; +Pipeline parse_tokstream(TokenVec tok_vec) { + TokStream tokstream = {.vec = tok_vec, .pos = 0}; Pipeline result = make_Pipeline(256); while (true) { Command cmd = parse_command(&tokstream); @@ -76,4 +79,5 @@ Pipeline parse_tokstream(TokenVec toks) { push_to_Pipeline(&result, (PipelineElement){.cmd = cmd, .conn = conn}); if (conn == CONN_EOL) break; } + return result; } diff --git a/typeutils.h b/typeutils.h index d83217d..e7aee6f 100644 --- a/typeutils.h +++ b/typeutils.h @@ -8,57 +8,94 @@ #include <stdio.h> -#define DECLARE_VEC(T, Name) \ - typedef struct { \ - T* items; \ - size_t count; \ - size_t cap; \ - size_t incr_step; \ - } Name; \ - static inline Name make_##Name(size_t step) { \ - return (Name) { \ - .items = malloc(step* sizeof(T)), \ - .count = 0, \ - .cap = step, \ - .incr_step = step, \ - }; \ - } \ - static inline T* push_to_##Name(Name* vec, T item) { \ - if (vec->count == vec->cap) { \ - vec->cap += vec->incr_step; \ - vec->items = realloc( \ - vec->items, \ - vec->cap * sizeof(T) \ - ); \ - } \ - vec->items[vec->count] = item; \ - T* ptr = &vec->items[vec->count]; \ - vec->count++; \ - return ptr; \ - } +#define DECLARE_VEC(T, Name) \ + typedef struct { \ + T **blocks; \ + size_t count; \ + size_t used; \ + size_t cap; \ + size_t block_size; \ + } Name; \ + \ + static inline Name make_##Name(size_t block_size) { \ + return (Name){ \ + .blocks = NULL, \ + .count = 0, \ + .used = 0, \ + .cap = 0, \ + .block_size = block_size, \ + }; \ + } \ + \ + static inline T *push_to_##Name(Name *vec, T item) { \ + size_t block_index = vec->count / vec->block_size; \ + size_t item_index = vec->count % vec->block_size; \ + \ + if (block_index == vec->used) { \ + if (vec->used == vec->cap) { \ + size_t new_cap = vec->cap \ + ? vec->cap * 2 \ + : 8; \ + \ + T **new_blocks = realloc( \ + vec->blocks, \ + new_cap * sizeof(T *) \ + ); \ + \ + if (!new_blocks) abort(); \ + \ + vec->blocks = new_blocks; \ + vec->cap = new_cap; \ + } \ + \ + vec->blocks[vec->used] = \ + malloc(vec->block_size * sizeof(T)); \ + \ + if (!vec->blocks[vec->used]) abort(); \ + \ + vec->used++; \ + } \ + \ + T *ptr = &vec->blocks[block_index][item_index]; \ + *ptr = item; \ + \ + vec->count++; \ + return ptr; \ + } \ + \ + static inline T* get_from_##Name(Name *vec, size_t index) { \ + if (index >= vec->count) return NULL; \ + \ + return &vec->blocks \ + [index / vec->block_size] \ + [index % vec->block_size]; \ + } DECLARE_VEC(char, String); -static void append_str_to_String(String* target, char* src_str) { - size_t required_size = - ((target->count + strlen(src_str)) / target->incr_step + 1) * target->incr_step; - if (required_size > target->cap) { - target->cap = required_size; - target->items = realloc(target->items, required_size * sizeof(char)); + +static void append_str_to_String(String* target, const char* src_str) { + size_t len = strlen(src_str); + + for (size_t i = 0; i < len; i++) { + push_to_String(target, src_str[i]); } - memcpy(target->items + target->count, src_str, strlen(src_str)); - target->count += strlen(src_str); } -static inline char* inner(String str) { - if (str.count == str.cap) { - str.items = realloc(str.items, (str.cap+1)*sizeof(char)); +static inline char* inner(String* str) { + char *out = malloc(str->count + 1); + if (!out) abort(); + + for (size_t i = 0; i < str->count; i++) { + out[i] = *get_from_String(str, i); } - str.items[str.count] = '\0'; - return str.items; + + out[str->count] = '\0'; + return out; } + #define DECLARE_MAYBE(T) \ typedef struct { \ bool some; \ |
