summaryrefslogtreecommitdiff
path: root/lex.c
diff options
context:
space:
mode:
Diffstat (limited to 'lex.c')
-rw-r--r--lex.c123
1 files changed, 84 insertions, 39 deletions
diff --git a/lex.c b/lex.c
index 9e29420..d7641a4 100644
--- a/lex.c
+++ b/lex.c
@@ -50,11 +50,10 @@ MaybeChunk lex_expansion_chunk(RawLine* line, RegionVec* reg_arena, QuotationMod
TokenVec inner_toks = lex_level(line, ')', reg_arena);
expect_char(line, ')');
expect_char(line, ')');
- push_to_RegionVec(
+ Region* reg_ptr = push_to_RegionVec(
reg_arena,
(Region){.mode = ARITHM, .tokens = inner_toks}
);
- Region* reg_ptr = &reg_arena->items[reg_arena->count]; // TODO: maybe have push() return a pointer [in the macro]
return (MaybeChunk){
.some = true,
.value = (Chunk){
@@ -66,11 +65,10 @@ MaybeChunk lex_expansion_chunk(RawLine* line, RegionVec* reg_arena, QuotationMod
} else {
TokenVec inner_toks = lex_level(line, ')', reg_arena);
expect_char(line, ')');
- push_to_RegionVec(
+ Region* reg_ptr = push_to_RegionVec(
reg_arena,
- (Region){.mode = CMD_SUB, .tokens = inner_toks}
+ (Region){.mode = CMDS, .tokens = inner_toks}
);
- Region* reg_ptr = &reg_arena->items[reg_arena->count];
return (MaybeChunk) {
.some = true,
.value = (Chunk){
@@ -164,65 +162,112 @@ Chunk collect_single_quoted_section(RawLine* line) {
}
+typedef struct {
+ TokenVec tokens;
+ Word word_germ;
+ String unq_liter_germ;
+} LexState;
+
+
+void close_literal_germ(LexState* state) {
+ if (state->unq_liter_germ.count > 0) {
+ push_to_Word(
+ &state->word_germ,
+ (Chunk){
+ .qmode = UN_Q,
+ .kind = LITERAL,
+ .as.literal_str = inner(state->unq_liter_germ)
+ }
+ );
+ state->unq_liter_germ = make_String(256);
+ }
+}
+
+void close_word_and_lit_germs(LexState* state) {
+ close_literal_germ(state);
+ if (state->word_germ.count > 0) {
+ push_to_TokenVec(&state->tokens, (Token){.kind = TOK_WORD, .as.word = state->word_germ});
+ state->word_germ = make_Word(256);
+ }
+}
TokenVec lex_level(RawLine* line, char until, RegionVec* reg_arena) {
- printf("\n\n==== START LEVEL ===\n\n");
- TokenVec tokens = make_TokenVec(256);
- Word curr_chunks = make_Word(256);
- String word_buf = make_String(256);
+ LexState state = {
+ .tokens = make_TokenVec(256),
+ .word_germ = make_Word(256),
+ .unq_liter_germ = make_String(256)
+ };
while (line->str[line->pos] != until) {
- printf("\n\nLoop %d %d %d (%s)\n", tokens.count, curr_chunks.count, word_buf.count, word_buf.items);
if (line->str[line->pos] == ' ') {
- if (word_buf.count > 0) {
- push_to_Word(
- &curr_chunks,
- (Chunk){.qmode = UN_Q, .kind = LITERAL, .as.literal_str = inner(word_buf)}
- );
- word_buf = make_String(256);
- }
- if (curr_chunks.count > 0) {
- push_to_TokenVec(&tokens, (Token){.kind = TOK_WORD, .as.word = curr_chunks});
- curr_chunks = make_Word(256);
- }
-
+ close_word_and_lit_germs(&state);
while (line->str[line->pos] == ' ') line->pos++;
+ continue;
}
switch (line->str[line->pos]) {
case '\'':
- push_to_Word(&curr_chunks, collect_single_quoted_section(line));
+ push_to_Word(&state.word_germ, collect_single_quoted_section(line));
break;
case '\"':
- lex_double_quoted_section(line, &curr_chunks, reg_arena);
+ lex_double_quoted_section(line, &state.word_germ, reg_arena);
break;
case '$':
line->pos++;
MaybeChunk mchunk = lex_expansion_chunk(line, reg_arena, UN_Q);
if (mchunk.some) {
- push_to_Word(&curr_chunks, mchunk.value);
+ push_to_Word(&state.word_germ, mchunk.value);
} else {
- push_to_String(&word_buf, '$');
+ push_to_String(&state.unq_liter_germ, '$');
+ }
+ break;
+ case '>':
+ close_word_and_lit_germs(&state);
+ line->pos++;
+
+ switch (line->str[line->pos]) {
+ case '(':
+ line->pos++;
+ TokenVec sub_regtoks = lex_level(line, ')', reg_arena);
+ Region subreg = {.mode = CMDS, .tokens = sub_regtoks};
+ Region* reg_ptr = push_to_RegionVec(reg_arena, subreg);
+ line->pos++;
+
+ push_to_TokenVec(&state.tokens, (Token){.kind = TOK_PROCSUB_OUT, .as.procsub_region = reg_ptr});
+ break;
+ case '>':
+ line->pos++;
+ push_to_TokenVec(&state.tokens, (Token){.kind = TOK_SPECIAL, .as.spec = WRITE_REDIR_APPEND});
+ break;
+ default:
+ push_to_TokenVec(&state.tokens, (Token){.kind = TOK_SPECIAL, .as.spec = WRITE_REDIR_TRUNC});
+ }
+ break;
+ case '<':
+ close_word_and_lit_germs(&state);
+ line->pos++;
+ if (line->str[line->pos] == '(') {
+ line->pos++;
+ TokenVec sub_regtoks = lex_level(line, ')', reg_arena);
+ Region subreg = {.mode = CMDS, .tokens = sub_regtoks};
+ Region* reg_ptr = push_to_RegionVec(reg_arena, subreg);
+ line->pos++;
+
+ push_to_TokenVec(&state.tokens, (Token){.kind = TOK_PROCSUB_IN, .as.procsub_region = reg_ptr});
+ break;
+ } else {
+ push_to_TokenVec(&state.tokens, (Token){.kind = TOK_SPECIAL, .as.spec = READ_REDIR});
}
break;
default:
- push_to_String(&word_buf, line->str[line->pos++]);
+ push_to_String(&state.unq_liter_germ, line->str[line->pos++]);
}
}
-
- if (word_buf.count > 0) {
- push_to_Word(
- &curr_chunks,
- (Chunk){.qmode = UN_Q, .kind = LITERAL, .as.literal_str = inner(word_buf)}
- );
- }
- if (curr_chunks.count > 0) {
- push_to_TokenVec(&tokens, (Token){.kind = TOK_WORD, .as.word = curr_chunks});
- }
- printf("\nFIN: %d %d %d\n\n", tokens.count, curr_chunks.count, word_buf.count);
- return tokens;
+ // TODO: handle until char _and_ EOL
+ close_word_and_lit_germs(&state);
+ return state.tokens;
}