frontend: Add parsing of shell blocks

Signed-off-by: Ian Moffett <ian@mirocom.org>
This commit is contained in:
2026-03-21 17:15:24 -04:00
parent c717e80636
commit 7c0f40abbf
4 changed files with 70 additions and 11 deletions

View File

@@ -1,6 +1,7 @@
.cc clang .cc clang
.ld lld-link .ld lld-link
# Shell block
CFLAGS :: CFLAGS ::
-Iinclude/ -Iinclude/
-mgeneral-regs-only -mgeneral-regs-only

View File

@@ -21,6 +21,8 @@
#include "common/ptrbox.h" #include "common/ptrbox.h"
#include "common/trace.h" #include "common/trace.h"
#define SHELL_BLOCK_TERMINATE '~'
/* /*
* Test if a given character counts as a whitespace character * Test if a given character counts as a whitespace character
* *
@@ -247,6 +249,69 @@ lexer_scan_directive(struct quip_state *state, struct token *tokres)
return -1; return -1;
} }
/*
* Scan a shell block
*
* @state: Quip state
* @tokres: Token result is written here
*
* Returns zero on success
*/
static int
lexer_scan_shellblock(struct quip_state *state, struct token *tokres)
{
char c, *buf;
size_t bufsz, bufcap;
bool is_leading = true;
bufsz = 0;
bufcap = 8;
if ((buf = malloc(bufcap)) == NULL) {
return -1;
}
for (;;) {
if ((c = lexer_consume(state, false)) == '\0') {
trace_error(state, "unexpected end of file within shellblock\n");
free(buf);
return -1;
}
/* Handle overflow if needed */
if (bufsz > bufcap - 1) {
bufcap += 8;
buf = realloc(buf, bufcap);
}
/* Handle newlines */
if (c == '\n') {
buf[bufsz++] = ' ';
is_leading = true;
continue;
}
if (c == SHELL_BLOCK_TERMINATE) {
buf[bufsz] = '\0';
break;
}
if (is_leading && lexer_is_ws(c)) {
continue;
}
is_leading = false;
buf[bufsz++] = c;
if (buf == NULL) {
return -1;
}
}
tokres->type = TT_SHELLBLOCK;
tokres->s = ptrbox_strdup(&state->ptrbox, buf);
free(buf);
return 0;
}
int int
lexer_scan(struct quip_state *state, struct token *tokres) lexer_scan(struct quip_state *state, struct token *tokres)
{ {
@@ -274,17 +339,12 @@ lexer_scan(struct quip_state *state, struct token *tokres)
case ':': case ':':
tokres->c = c; tokres->c = c;
if ((c = lexer_consume(state, false)) == ':') { if ((c = lexer_consume(state, false)) == ':') {
tokres->type = TT_COLONDUB; return lexer_scan_shellblock(state, tokres);
return 0;
} }
lexer_putback(state, c); lexer_putback(state, c);
tokres->type = TT_COLON; tokres->type = TT_COLON;
return 0; return 0;
case '~':
tokres->type = TT_TILDE;
tokres->c = c;
return 0;
default: default:
if (lexer_scan_name(state, c, tokres) == 0) { if (lexer_scan_name(state, c, tokres) == 0) {
return 0; return 0;

View File

@@ -37,11 +37,10 @@ static const char *toktab[] = {
[TT_NONE] = symtok("none"), [TT_NONE] = symtok("none"),
[TT_NAME] = symtok("name"), [TT_NAME] = symtok("name"),
[TT_NEWLINE] = symtok("newline"), [TT_NEWLINE] = symtok("newline"),
[TT_SHELLBLOCK] = symtok("shellblock"),
[TT_CC] = qtok(".cc"), [TT_CC] = qtok(".cc"),
[TT_LD] = qtok(".ld"), [TT_LD] = qtok(".ld"),
[TT_COLON] = qtok(":"), [TT_COLON] = qtok(":")
[TT_TILDE] = qtok("~"),
[TT_COLONDUB] = qtok("::")
}; };
int int

View File

@@ -18,11 +18,10 @@ typedef enum {
TT_NONE, /* [none] */ TT_NONE, /* [none] */
TT_NAME, /* [name] */ TT_NAME, /* [name] */
TT_NEWLINE, /* [newline] */ TT_NEWLINE, /* [newline] */
TT_SHELLBLOCK, /* [shellblock] */
TT_CC, /* '.cc' */ TT_CC, /* '.cc' */
TT_LD, /* '.ld' */ TT_LD, /* '.ld' */
TT_COLON, /* ':' */ TT_COLON, /* ':' */
TT_TILDE, /* '~' */
TT_COLONDUB, /* '::' */
} tt_t; } tt_t;
/* /*