parse: improve command arg parsing

This commit is contained in:
2026-05-09 21:21:51 +01:00
parent 7d95d57f98
commit cfaf53040b
7 changed files with 255 additions and 203 deletions
+166 -147
View File
@@ -48,29 +48,21 @@ static struct lex_token_def symbols[] = {
}; };
static const size_t nr_symbols = sizeof symbols / sizeof symbols[0]; static const size_t nr_symbols = sizeof symbols / sizeof symbols[0];
typedef enum bshell_status (*pump_token_impl)(struct lex_ctx *, enum lex_flags); typedef enum bshell_status (*pump_token_impl)(struct lex_ctx *);
static enum bshell_status do_pump_token_normal( static enum bshell_status do_pump_token_normal(struct lex_ctx *);
struct lex_ctx *, static enum bshell_status do_pump_token_string(struct lex_ctx *ctx);
enum lex_flags);
static enum bshell_status do_pump_token_string(
struct lex_ctx *ctx,
enum lex_flags);
static const pump_token_impl token_pump_functions[] = { static const pump_token_impl token_pump_functions[] = {
[LEX_STATE_NORMAL] = do_pump_token_normal, [LEX_STATE_NORMAL] = do_pump_token_normal,
[LEX_STATE_STRING] = do_pump_token_string, [LEX_STATE_STRING] = do_pump_token_string,
[LEX_STATE_INTERPOLATION] = do_pump_token_normal, [LEX_STATE_INTERPOLATION] = do_pump_token_normal,
}; };
static bool char_can_begin_symbol( static bool char_can_begin_symbol(struct lex_ctx *ctx, char c);
struct lex_ctx *ctx,
char c,
enum lex_flags flags);
static bool char_can_begin_symbol_in_context( static bool char_can_begin_symbol_in_context(
struct lex_ctx *ctx, struct lex_ctx *ctx,
char c, char c,
enum token_type context, enum token_type context);
enum lex_flags flags);
static struct lex_state *push_lex_state( static struct lex_state *push_lex_state(
struct lex_ctx *ctx, struct lex_ctx *ctx,
@@ -209,6 +201,7 @@ enum bshell_status lex_ctx_init(
ctx->lex_status = BSHELL_SUCCESS; ctx->lex_status = BSHELL_SUCCESS;
ctx->lex_buf = fx_stringstream_create(); ctx->lex_buf = fx_stringstream_create();
ctx->lex_sym_tree = build_symbol_tree(); ctx->lex_sym_tree = build_symbol_tree();
ctx->lex_wordbuf = fx_string_create();
push_lex_state(ctx, LEX_STATE_NORMAL); push_lex_state(ctx, LEX_STATE_NORMAL);
ctx->lex_src = src; ctx->lex_src = src;
ctx->lex_ch = FX_WCHAR_INVALID; ctx->lex_ch = FX_WCHAR_INVALID;
@@ -278,6 +271,10 @@ static fx_wchar peek_char_noread(struct lex_ctx *ctx)
static void __advance_char(struct lex_ctx *ctx, bool noread) static void __advance_char(struct lex_ctx *ctx, bool noread)
{ {
if (!fx_wchar_is_space(ctx->lex_ch)) {
fx_string_append_wc(ctx->lex_wordbuf, ctx->lex_ch);
}
if (ctx->lex_ch != FX_WCHAR_INVALID) { if (ctx->lex_ch != FX_WCHAR_INVALID) {
ctx->lex_ch = FX_WCHAR_INVALID; ctx->lex_ch = FX_WCHAR_INVALID;
return; return;
@@ -422,99 +419,37 @@ static bool convert_word_to_int(
return ok; return ok;
} }
static struct lex_token *create_alt_token( static struct lex_token *get_next_token(struct lex_ctx *ctx)
struct lex_ctx *ctx,
struct lex_token *tok,
enum lex_flags flags)
{
if (ctx->lex_alt) {
return ctx->lex_alt;
}
bool converted = false;
struct lex_token alt = {0};
if (flags & LEX_ENABLE_KEYWORD) {
converted = convert_word_to_keyword(tok, &alt);
}
if (!converted && (flags & LEX_ENABLE_INT)) {
converted = convert_word_to_int(tok, &alt);
}
if (!converted) {
return NULL;
}
ctx->lex_alt = lex_token_create(alt.tok_type);
if (!ctx->lex_alt) {
ctx->lex_status = BSHELL_ERR_NO_MEMORY;
return NULL;
}
memcpy(ctx->lex_alt, &alt, sizeof alt);
return ctx->lex_alt;
}
static struct lex_token *get_next_token(
struct lex_ctx *ctx,
enum lex_flags flags)
{ {
fx_queue_entry *entry = fx_queue_first(&ctx->lex_tokens); fx_queue_entry *entry = fx_queue_first(&ctx->lex_tokens);
struct lex_token *tok = fx_unbox(struct lex_token, entry, tok_entry); return fx_unbox(struct lex_token, entry, tok_entry);
}
if (!tok || !CONVERSION_REQUESTED(flags)) { static struct lex_token *get_next_word(struct lex_ctx *ctx)
return tok; {
} fx_queue_entry *entry = fx_queue_first(&ctx->lex_words);
return fx_unbox(struct lex_token, entry, tok_entry);
if (ctx->lex_alt) {
return ctx->lex_alt;
}
ctx->lex_alt = create_alt_token(ctx, tok, flags);
return ctx->lex_alt ? ctx->lex_alt : tok;
} }
static void enqueue_token(struct lex_ctx *ctx, struct lex_token *tok) static void enqueue_token(struct lex_ctx *ctx, struct lex_token *tok)
{ {
if (tok && (ctx->lex_flags & LEX_PRINT_TOKENS)) {
print_lex_token(tok);
}
fx_queue_push_back(&ctx->lex_tokens, &tok->tok_entry); fx_queue_push_back(&ctx->lex_tokens, &tok->tok_entry);
} }
static struct lex_token *dequeue_next_token( static struct lex_token *dequeue_next_token(struct lex_ctx *ctx)
struct lex_ctx *ctx,
enum lex_flags flags)
{ {
fx_queue_entry *entry = fx_queue_pop_front(&ctx->lex_tokens); fx_queue_entry *entry = fx_queue_pop_front(&ctx->lex_tokens);
struct lex_token *tok = fx_unbox(struct lex_token, entry, tok_entry); return fx_unbox(struct lex_token, entry, tok_entry);
}
if (!tok || !CONVERSION_REQUESTED(flags)) { static struct lex_token *dequeue_next_word(struct lex_ctx *ctx)
if (ctx->lex_alt) { {
lex_token_destroy(ctx->lex_alt); fx_queue_entry *entry = fx_queue_pop_front(&ctx->lex_words);
ctx->lex_alt = NULL; return fx_unbox(struct lex_token, entry, tok_entry);
}
return tok;
}
if (ctx->lex_alt) {
lex_token_destroy(tok);
tok = ctx->lex_alt;
ctx->lex_alt = NULL;
return tok;
}
ctx->lex_alt = create_alt_token(ctx, tok, flags);
if (ctx->lex_alt) {
lex_token_destroy(tok);
tok = ctx->lex_alt;
ctx->lex_alt = NULL;
}
return tok;
} }
static fx_string *get_temp_string(struct lex_ctx *ctx) static fx_string *get_temp_string(struct lex_ctx *ctx)
@@ -541,7 +476,7 @@ static enum bshell_status push_symbol(
return BSHELL_SUCCESS; return BSHELL_SUCCESS;
} }
static enum bshell_status read_word(struct lex_ctx *ctx, enum lex_flags flags) static enum bshell_status read_word(struct lex_ctx *ctx)
{ {
fx_string *tmp = get_temp_string(ctx); fx_string *tmp = get_temp_string(ctx);
bool word_is_number = false; bool word_is_number = false;
@@ -558,12 +493,12 @@ static enum bshell_status read_word(struct lex_ctx *ctx, enum lex_flags flags)
break; break;
} }
if (word_is_number && char_can_begin_symbol(ctx, c, flags)) { if (word_is_number && char_can_begin_symbol(ctx, c)) {
done = true; done = true;
break; break;
} }
if (char_can_begin_symbol_in_context(ctx, c, TOK_WORD, flags)) { if (char_can_begin_symbol_in_context(ctx, c, TOK_WORD)) {
done = true; done = true;
break; break;
} }
@@ -851,7 +786,7 @@ static enum bshell_status read_interpolation_marker(struct lex_ctx *ctx)
return BSHELL_SUCCESS; return BSHELL_SUCCESS;
} }
static enum bshell_status read_symbol(struct lex_ctx *ctx, enum lex_flags flags) static enum bshell_status read_symbol(struct lex_ctx *ctx)
{ {
struct lex_state *state = get_lex_state(ctx); struct lex_state *state = get_lex_state(ctx);
enum lex_token_flags required_flags = 0; enum lex_token_flags required_flags = 0;
@@ -859,10 +794,6 @@ static enum bshell_status read_symbol(struct lex_ctx *ctx, enum lex_flags flags)
required_flags |= LEX_TOKEN_ENABLE_IN_STRING; required_flags |= LEX_TOKEN_ENABLE_IN_STRING;
} }
if (!(flags & LEX_ENABLE_SYMBOL)) {
required_flags |= LEX_TOKEN_ENABLE_IN_WORD;
}
struct lex_symbol_node *node = ctx->lex_sym_tree; struct lex_symbol_node *node = ctx->lex_sym_tree;
char prev = 0; char prev = 0;
@@ -932,10 +863,7 @@ static enum bshell_status read_symbol(struct lex_ctx *ctx, enum lex_flags flags)
return BSHELL_SUCCESS; return BSHELL_SUCCESS;
} }
static bool char_can_begin_symbol( static bool char_can_begin_symbol(struct lex_ctx *ctx, char c)
struct lex_ctx *ctx,
char c,
enum lex_flags flags)
{ {
struct lex_state *state = get_lex_state(ctx); struct lex_state *state = get_lex_state(ctx);
enum lex_token_flags required_flags = 0; enum lex_token_flags required_flags = 0;
@@ -943,10 +871,6 @@ static bool char_can_begin_symbol(
required_flags |= LEX_TOKEN_ENABLE_IN_STRING; required_flags |= LEX_TOKEN_ENABLE_IN_STRING;
} }
if (!(flags & LEX_ENABLE_SYMBOL)) {
required_flags |= LEX_TOKEN_ENABLE_IN_WORD;
}
for (size_t i = 0; i < nr_symbols; i++) { for (size_t i = 0; i < nr_symbols; i++) {
if (symbols[i].name[0] != c) { if (symbols[i].name[0] != c) {
continue; continue;
@@ -965,8 +889,7 @@ static bool char_can_begin_symbol(
static bool char_can_begin_symbol_in_context( static bool char_can_begin_symbol_in_context(
struct lex_ctx *ctx, struct lex_ctx *ctx,
char c, char c,
enum token_type context, enum token_type context)
enum lex_flags flags)
{ {
enum lex_token_flags required_flags = 0; enum lex_token_flags required_flags = 0;
switch (context) { switch (context) {
@@ -1011,7 +934,7 @@ static enum bshell_status read_string_content(struct lex_ctx *ctx)
break; break;
} }
if (char_can_begin_symbol(ctx, c, 0)) { if (char_can_begin_symbol(ctx, c)) {
break; break;
} }
@@ -1032,16 +955,14 @@ static enum bshell_status read_string_content(struct lex_ctx *ctx)
return BSHELL_SUCCESS; return BSHELL_SUCCESS;
} }
static enum bshell_status do_pump_token_string( static enum bshell_status do_pump_token_string(struct lex_ctx *ctx)
struct lex_ctx *ctx,
enum lex_flags flags)
{ {
fx_wchar c = peek_char(ctx); fx_wchar c = peek_char(ctx);
enum bshell_status status = BSHELL_SUCCESS; enum bshell_status status = BSHELL_SUCCESS;
bool ok = false; bool ok = false;
if (char_can_begin_symbol(ctx, c, flags)) { if (char_can_begin_symbol(ctx, c)) {
status = read_symbol(ctx, flags); status = read_symbol(ctx);
ok = true; ok = true;
} }
@@ -1052,15 +973,32 @@ static enum bshell_status do_pump_token_string(
return status; return status;
} }
static enum bshell_status do_pump_token_normal( static void flush_wordbuf(struct lex_ctx *ctx)
struct lex_ctx *ctx, {
enum lex_flags flags) if (fx_string_get_size(ctx->lex_wordbuf, FX_STRLEN_NORMAL) == 0) {
return;
}
struct lex_token *tok = lex_token_create_with_string(
TOK_WORD,
fx_string_get_cstr(ctx->lex_wordbuf));
fx_queue_push_back(&ctx->lex_words, &tok->tok_entry);
fx_string_clear(ctx->lex_wordbuf);
}
static enum bshell_status do_pump_token_normal(struct lex_ctx *ctx)
{ {
enum bshell_status status = BSHELL_SUCCESS; enum bshell_status status = BSHELL_SUCCESS;
fx_wchar c = peek_char(ctx); fx_wchar c = peek_char(ctx);
bool whitespace = false;
bool newline = false; bool newline = false;
if (fx_wchar_is_space(c)) {
flush_wordbuf(ctx);
whitespace = true;
}
while (fx_wchar_is_space(c)) { while (fx_wchar_is_space(c)) {
if (c == '\n') { if (c == '\n') {
newline = true; newline = true;
@@ -1073,6 +1011,9 @@ static enum bshell_status do_pump_token_normal(
if (newline) { if (newline) {
struct lex_token *tok = lex_token_create(TOK_LINEFEED); struct lex_token *tok = lex_token_create(TOK_LINEFEED);
enqueue_token(ctx, tok); enqueue_token(ctx, tok);
}
if (whitespace) {
return BSHELL_SUCCESS; return BSHELL_SUCCESS;
} }
@@ -1080,70 +1021,148 @@ static enum bshell_status do_pump_token_normal(
return read_flag(ctx); return read_flag(ctx);
} }
if (char_can_begin_symbol(ctx, c, flags)) { if (char_can_begin_symbol(ctx, c)) {
return read_symbol(ctx, flags); return read_symbol(ctx);
} }
return read_word(ctx, flags); return read_word(ctx);
} }
static enum bshell_status pump_tokens(struct lex_ctx *ctx, enum lex_flags flags) static enum bshell_status pump_tokens(struct lex_ctx *ctx)
{ {
enum bshell_status status = BSHELL_SUCCESS; enum bshell_status status = BSHELL_SUCCESS;
while (fx_queue_empty(&ctx->lex_tokens) && status == BSHELL_SUCCESS) { while (fx_queue_empty(&ctx->lex_words) && status == BSHELL_SUCCESS) {
struct lex_state *state = get_lex_state(ctx); struct lex_state *state = get_lex_state(ctx);
pump_token_impl impl = token_pump_functions[state->s_type]; pump_token_impl impl = token_pump_functions[state->s_type];
status = impl(ctx, flags); status = impl(ctx);
} }
return status; return status;
} }
struct lex_token *lex_ctx_peek(struct lex_ctx *ctx, enum lex_flags flags) static bool any_tokens_available(struct lex_ctx *ctx)
{ {
struct lex_token *tok = get_next_token(ctx, flags); return !fx_queue_empty(&ctx->lex_tokens)
|| !fx_queue_empty(&ctx->lex_words);
}
static void discard_all_tokens(struct lex_ctx *ctx)
{
fx_queue_entry *cur = fx_queue_first(&ctx->lex_tokens);
while (cur) {
struct lex_token *tok
= fx_unbox(struct lex_token, cur, tok_entry);
if (tok->tok_type == TOK_LINEFEED) {
break;
}
fx_queue_pop_front(&ctx->lex_tokens);
lex_token_destroy(tok);
cur = fx_queue_first(&ctx->lex_tokens);
}
}
static void discard_all_words(struct lex_ctx *ctx)
{
fx_queue_entry *cur = fx_queue_pop_front(&ctx->lex_words);
while (cur) {
struct lex_token *tok
= fx_unbox(struct lex_token, cur, tok_entry);
lex_token_destroy(tok);
cur = fx_queue_pop_front(&ctx->lex_words);
}
}
struct lex_token *lex_ctx_peek(struct lex_ctx *ctx)
{
struct lex_token *tok = get_next_token(ctx);
if (tok) { if (tok) {
return tok; return tok;
} }
pump_tokens(ctx, flags); discard_all_words(ctx);
tok = get_next_token(ctx, flags); pump_tokens(ctx);
if (tok && (ctx->lex_flags & LEX_PRINT_TOKENS)) { tok = get_next_token(ctx);
print_lex_token(tok);
}
return tok; return tok;
} }
struct lex_token *lex_ctx_claim(struct lex_ctx *ctx, enum lex_flags flags) struct lex_token *lex_ctx_peek_word(struct lex_ctx *ctx)
{ {
struct lex_token *tok = dequeue_next_token(ctx, flags); struct lex_token *tok = get_next_word(ctx);
if (tok) { if (tok) {
return tok; return tok;
} }
if (fx_queue_empty(&ctx->lex_tokens)) { discard_all_tokens(ctx);
pump_tokens(ctx, flags); pump_tokens(ctx);
tok = get_next_token(ctx);
tok = get_next_token(ctx, flags); return tok;
if (tok && (ctx->lex_flags & LEX_PRINT_TOKENS)) {
print_lex_token(tok);
}
}
return dequeue_next_token(ctx, flags);
} }
void lex_ctx_discard(struct lex_ctx *ctx, enum lex_flags flags) struct lex_token *lex_ctx_claim(struct lex_ctx *ctx)
{ {
struct lex_token *tok = dequeue_next_token(ctx, 0); struct lex_token *tok = dequeue_next_token(ctx);
if (tok) {
struct lex_token *tmp = get_next_token(ctx);
if (tmp && tmp->tok_type == TOK_LINEFEED) {
tmp = dequeue_next_word(ctx);
lex_token_destroy(tmp);
}
return tok;
}
if (fx_queue_empty(&ctx->lex_tokens)) {
pump_tokens(ctx);
tok = get_next_token(ctx);
}
return dequeue_next_token(ctx);
}
struct lex_token *lex_ctx_claim_word(struct lex_ctx *ctx)
{
/* since we're claiming the whole word, discard any sub-tokens already
* generated up to the next linefeed */
discard_all_tokens(ctx);
struct lex_token *tok = dequeue_next_word(ctx);
if (tok) {
return tok;
}
if (fx_queue_empty(&ctx->lex_words)) {
pump_tokens(ctx);
tok = get_next_token(ctx);
}
return dequeue_next_word(ctx);
}
void lex_ctx_discard(struct lex_ctx *ctx)
{
struct lex_token *tok = dequeue_next_token(ctx);
if (tok) { if (tok) {
lex_token_destroy(tok); lex_token_destroy(tok);
tok = get_next_token(ctx);
/* if the next token is a linefeed, we've reached the end
* of the current word, and should discard it */
if (tok && tok->tok_type == TOK_LINEFEED) {
tok = dequeue_next_word(ctx);
lex_token_destroy(tok);
}
return; return;
} }
/* request more tokens if necessary */
if (fx_queue_empty(&ctx->lex_tokens)) { if (fx_queue_empty(&ctx->lex_tokens)) {
pump_tokens(ctx, flags); pump_tokens(ctx);
} }
} }
+15 -10
View File
@@ -54,12 +54,19 @@ struct lex_state {
struct lex_ctx { struct lex_ctx {
enum lex_flags lex_flags; enum lex_flags lex_flags;
fx_queue lex_tokens; /* lex_ctx maintains two queues of tokens.
* lex_words is a simple queue of all WORDS scanned by the lexer,
* without any further parsing applied to potentially convert the words
* into TOK_INT, TOK_SYMBOL, etc.
* lex_tokens represent all of the tokens generated by applying the
* aforementioned parsing.
* the two queues are kept in sync such that, as tokens are dequeued
* from one queue, the other queue is moved forward too. */
fx_queue lex_tokens, lex_words;
struct line_source *lex_src; struct line_source *lex_src;
fx_stringstream *lex_buf; fx_stringstream *lex_buf;
fx_string *lex_tmp; fx_string *lex_tmp, *lex_wordbuf;
fx_wchar lex_ch; fx_wchar lex_ch;
struct lex_token *lex_alt;
fx_queue lex_state; fx_queue lex_state;
struct lex_symbol_node *lex_sym_tree; struct lex_symbol_node *lex_sym_tree;
enum bshell_status lex_status; enum bshell_status lex_status;
@@ -71,12 +78,10 @@ extern enum bshell_status lex_ctx_init(
struct line_source *src); struct line_source *src);
extern enum bshell_status lex_ctx_cleanup(struct lex_ctx *ctx); extern enum bshell_status lex_ctx_cleanup(struct lex_ctx *ctx);
extern struct lex_token *lex_ctx_peek( extern struct lex_token *lex_ctx_peek(struct lex_ctx *ctx);
struct lex_ctx *ctx, extern struct lex_token *lex_ctx_peek_word(struct lex_ctx *ctx);
enum lex_flags flags); extern struct lex_token *lex_ctx_claim(struct lex_ctx *ctx);
extern struct lex_token *lex_ctx_claim( extern struct lex_token *lex_ctx_claim_word(struct lex_ctx *ctx);
struct lex_ctx *ctx, extern void lex_ctx_discard(struct lex_ctx *ctx);
enum lex_flags flags);
extern void lex_ctx_discard(struct lex_ctx *ctx, enum lex_flags flags);
#endif #endif
+6 -9
View File
@@ -12,29 +12,26 @@ enum parse_operand_flags {
OPERAND_BASIC = 0x01u, OPERAND_BASIC = 0x01u,
}; };
extern struct lex_token *peek_token( extern struct lex_token *peek_token(struct parse_ctx *ctx);
struct parse_ctx *ctx, extern enum token_type peek_token_type(struct parse_ctx *ctx);
enum lex_flags flags);
extern enum token_type peek_token_type(
struct parse_ctx *ctx,
enum lex_flags flags);
extern enum token_keyword peek_unknown_keyword(struct parse_ctx *ctx); extern enum token_keyword peek_unknown_keyword(struct parse_ctx *ctx);
extern enum token_symbol peek_unknown_symbol(struct parse_ctx *ctx); extern enum token_symbol peek_unknown_symbol(struct parse_ctx *ctx);
extern bool peek_int(struct parse_ctx *ctx); extern bool peek_int(struct parse_ctx *ctx);
extern struct lex_token *claim_token( extern struct lex_token *claim_token(struct parse_ctx *ctx);
struct parse_ctx *ctx, extern struct lex_token *claim_glob_word(struct parse_ctx *ctx);
enum lex_flags flags);
extern void discard_token(struct parse_ctx *ctx); extern void discard_token(struct parse_ctx *ctx);
extern bool peek_linefeed(struct parse_ctx *ctx); extern bool peek_linefeed(struct parse_ctx *ctx);
extern bool peek_symbol(struct parse_ctx *ctx, enum token_symbol sym); extern bool peek_symbol(struct parse_ctx *ctx, enum token_symbol sym);
extern struct lex_token *peek_glob_word(struct parse_ctx *ctx);
extern bool parse_linefeed(struct parse_ctx *ctx); extern bool parse_linefeed(struct parse_ctx *ctx);
extern bool parse_symbol(struct parse_ctx *ctx, enum token_symbol sym); extern bool parse_symbol(struct parse_ctx *ctx, enum token_symbol sym);
extern bool parse_keyword(struct parse_ctx *ctx, enum token_keyword kw); extern bool parse_keyword(struct parse_ctx *ctx, enum token_keyword kw);
extern bool parse_int(struct parse_ctx *ctx, long long *out); extern bool parse_int(struct parse_ctx *ctx, long long *out);
extern bool parse_flag(struct parse_ctx *ctx, struct lex_token **out); extern bool parse_flag(struct parse_ctx *ctx, struct lex_token **out);
extern struct lex_token *parse_glob_word(struct parse_ctx *ctx);
extern bool peek_arith_expr(struct parse_ctx *ctx); extern bool peek_arith_expr(struct parse_ctx *ctx);
extern bool parse_arith_expr(struct parse_ctx *ctx, struct ast_node **out); extern bool parse_arith_expr(struct parse_ctx *ctx, struct ast_node **out);
+17 -1
View File
@@ -2,7 +2,23 @@
bool peek_arith_expr(struct parse_ctx *ctx) bool peek_arith_expr(struct parse_ctx *ctx)
{ {
return false; switch (peek_token_type(ctx)) {
case TOK_SYMBOL:
switch (peek_unknown_symbol(ctx)) {
case SYM_PLUS:
case SYM_HYPHEN:
return true;
default:
return false;
}
case TOK_INT:
case TOK_DOUBLE:
case TOK_STRING:
case TOK_STR_START:
return true;
default:
return false;
}
} }
bool parse_arith_expr(struct parse_ctx *ctx, struct ast_node **out) bool parse_arith_expr(struct parse_ctx *ctx, struct ast_node **out)
+27 -13
View File
@@ -4,7 +4,7 @@
static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out) static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out)
{ {
struct lex_token *tok = peek_token(ctx, 0); struct lex_token *tok = peek_token(ctx);
if (!tok) { if (!tok) {
return false; return false;
} }
@@ -20,11 +20,12 @@ static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out)
return false; return false;
} }
n->n_value = claim_token(ctx, 0); n->n_value = claim_token(ctx);
*out = (struct ast_node *)n; *out = (struct ast_node *)n;
return true; return true;
} }
#if 0
case TOK_FLAG: { case TOK_FLAG: {
struct word_ast_node *n struct word_ast_node *n
= (struct word_ast_node *)ast_node_create(AST_WORD); = (struct word_ast_node *)ast_node_create(AST_WORD);
@@ -33,10 +34,11 @@ static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out)
return false; return false;
} }
n->n_value = claim_token(ctx, 0); n->n_value = claim_token(ctx);
*out = (struct ast_node *)n; *out = (struct ast_node *)n;
return true; return true;
} }
#endif
case TOK_VAR: { case TOK_VAR: {
struct var_ast_node *n struct var_ast_node *n
@@ -46,7 +48,7 @@ static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out)
return false; return false;
} }
n->n_ident = claim_token(ctx, 0); n->n_ident = claim_token(ctx);
*out = (struct ast_node *)n; *out = (struct ast_node *)n;
return true; return true;
} }
@@ -60,7 +62,7 @@ static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out)
return false; return false;
} }
n->n_ident = claim_token(ctx, 0); n->n_ident = claim_token(ctx);
*out = (struct ast_node *)n; *out = (struct ast_node *)n;
return true; return true;
} }
@@ -73,12 +75,24 @@ static bool parse_cmdcall_arg(struct parse_ctx *ctx, struct ast_node **out)
return false; return false;
} }
n->n_value = claim_token(ctx, 0); n->n_value = claim_token(ctx);
*out = (struct ast_node *)n;
return true;
}
default: {
struct word_ast_node *n
= (struct word_ast_node *)ast_node_create(AST_WORD);
if (!n) {
ctx->p_status = BSHELL_ERR_NO_MEMORY;
return false;
}
n->n_value = claim_glob_word(ctx);
*out = (struct ast_node *)n; *out = (struct ast_node *)n;
return true; return true;
} }
default:
return false; return false;
} }
@@ -125,7 +139,7 @@ static bool parse_redirect_to_file_squashed(
const char *str, const char *str,
struct ast_node **out) struct ast_node **out)
{ {
struct lex_token *tok = peek_token(ctx, 0); struct lex_token *tok = peek_token(ctx);
if (*str == '\0') { if (*str == '\0') {
return false; return false;
} }
@@ -140,7 +154,7 @@ static bool parse_redirect_to_file_squashed(
redirect->n_out_is_expr = false; redirect->n_out_is_expr = false;
redirect->n_out_path = str; redirect->n_out_path = str;
redirect->n_out_tok = claim_token(ctx, 0); redirect->n_out_tok = claim_token(ctx);
*out = (struct ast_node *)redirect; *out = (struct ast_node *)redirect;
return true; return true;
@@ -174,7 +188,7 @@ static bool parse_redirect_to_file_separate(
bool parse_redirect(struct parse_ctx *ctx, struct ast_node **out) bool parse_redirect(struct parse_ctx *ctx, struct ast_node **out)
{ {
struct lex_token *tok = peek_token(ctx, 0); struct lex_token *tok = peek_token(ctx);
if (!tok || tok->tok_type != TOK_WORD) { if (!tok || tok->tok_type != TOK_WORD) {
return false; return false;
} }
@@ -234,7 +248,7 @@ static bool peek_cmdcall_item(struct parse_ctx *ctx, bool unrestricted)
* a command with this token as its name, the call operator must be * a command with this token as its name, the call operator must be
* used. * used.
*/ */
switch (peek_token_type(ctx, LEX_ENABLE_INT | LEX_ENABLE_KEYWORD)) { switch (peek_token_type(ctx)) {
case TOK_KEYWORD: case TOK_KEYWORD:
case TOK_INT: case TOK_INT:
case TOK_DOUBLE: case TOK_DOUBLE:
@@ -285,7 +299,7 @@ bool parse_cmdcall(struct parse_ctx *ctx, struct ast_node **out)
return false; return false;
} }
struct lex_token *tok = peek_token(ctx, 0); struct lex_token *tok = peek_token(ctx);
if (!tok) { if (!tok) {
return false; return false;
} }
@@ -301,7 +315,7 @@ bool parse_cmdcall(struct parse_ctx *ctx, struct ast_node **out)
break; break;
} }
struct lex_token *tok = peek_token(ctx, 0); struct lex_token *tok = peek_token(ctx);
if (!tok) { if (!tok) {
break; break;
} }
+4 -5
View File
@@ -3,13 +3,12 @@
bool parse_expr(struct parse_ctx *ctx, struct ast_node **out) bool parse_expr(struct parse_ctx *ctx, struct ast_node **out)
{ {
bool ok = false; bool ok = false;
if (peek_command(ctx)) { if (peek_arith_expr(ctx)) {
ok = parse_command(ctx, out);
}
if (!ok && peek_arith_expr(ctx)) {
ok = parse_arith_expr(ctx, out); ok = parse_arith_expr(ctx, out);
} }
if (!ok && peek_command(ctx)) {
ok = parse_command(ctx, out);
}
return ok; return ok;
} }
+20 -18
View File
@@ -3,47 +3,49 @@
#include "../syntax.h" #include "../syntax.h"
#include "../token.h" #include "../token.h"
#define DEFAULT_LEX_FLAGS \ struct lex_token *claim_token(struct parse_ctx *ctx)
(LEX_ENABLE_INT | LEX_ENABLE_KEYWORD | LEX_ENABLE_SYMBOL)
struct lex_token *claim_token(struct parse_ctx *ctx, enum lex_flags flags)
{ {
return lex_ctx_claim(ctx->p_src, flags); return lex_ctx_claim(ctx->p_src);
}
struct lex_token *claim_glob_word(struct parse_ctx *ctx)
{
return lex_ctx_claim_word(ctx->p_src);
} }
void discard_token(struct parse_ctx *ctx) void discard_token(struct parse_ctx *ctx)
{ {
return lex_ctx_discard(ctx->p_src, DEFAULT_LEX_FLAGS); return lex_ctx_discard(ctx->p_src);
} }
struct lex_token *peek_token(struct parse_ctx *ctx, enum lex_flags flags) struct lex_token *peek_token(struct parse_ctx *ctx)
{ {
return lex_ctx_peek(ctx->p_src, flags); return lex_ctx_peek(ctx->p_src);
} }
enum token_type peek_token_type(struct parse_ctx *ctx, enum lex_flags flags) enum token_type peek_token_type(struct parse_ctx *ctx)
{ {
struct lex_token *tok = peek_token(ctx, flags); struct lex_token *tok = peek_token(ctx);
return tok ? tok->tok_type : TOK_NONE; return tok ? tok->tok_type : TOK_NONE;
} }
enum token_symbol peek_unknown_symbol(struct parse_ctx *ctx) enum token_symbol peek_unknown_symbol(struct parse_ctx *ctx)
{ {
struct lex_token *tok = peek_token(ctx, DEFAULT_LEX_FLAGS); struct lex_token *tok = peek_token(ctx);
return (tok && tok->tok_type == TOK_SYMBOL) ? tok->tok_symbol return (tok && tok->tok_type == TOK_SYMBOL) ? tok->tok_symbol
: SYM_NONE; : SYM_NONE;
} }
enum token_keyword peek_unknown_keyword(struct parse_ctx *ctx) enum token_keyword peek_unknown_keyword(struct parse_ctx *ctx)
{ {
struct lex_token *tok = peek_token(ctx, DEFAULT_LEX_FLAGS); struct lex_token *tok = peek_token(ctx);
return (tok && tok->tok_type == TOK_KEYWORD) ? tok->tok_keyword return (tok && tok->tok_type == TOK_KEYWORD) ? tok->tok_keyword
: KW_NONE; : KW_NONE;
} }
bool peek_linefeed(struct parse_ctx *ctx) bool peek_linefeed(struct parse_ctx *ctx)
{ {
struct lex_token *tok = peek_token(ctx, DEFAULT_LEX_FLAGS); struct lex_token *tok = peek_token(ctx);
if (tok && tok->tok_type == TOK_LINEFEED) { if (tok && tok->tok_type == TOK_LINEFEED) {
return true; return true;
} }
@@ -53,7 +55,7 @@ bool peek_linefeed(struct parse_ctx *ctx)
bool peek_symbol(struct parse_ctx *ctx, enum token_symbol sym) bool peek_symbol(struct parse_ctx *ctx, enum token_symbol sym)
{ {
struct lex_token *tok = peek_token(ctx, DEFAULT_LEX_FLAGS); struct lex_token *tok = peek_token(ctx);
if (!tok) { if (!tok) {
return false; return false;
} }
@@ -71,7 +73,7 @@ bool peek_symbol(struct parse_ctx *ctx, enum token_symbol sym)
bool parse_linefeed(struct parse_ctx *ctx) bool parse_linefeed(struct parse_ctx *ctx)
{ {
struct lex_token *tok = peek_token(ctx, DEFAULT_LEX_FLAGS); struct lex_token *tok = peek_token(ctx);
if (tok && tok->tok_type == TOK_LINEFEED) { if (tok && tok->tok_type == TOK_LINEFEED) {
discard_token(ctx); discard_token(ctx);
return true; return true;
@@ -82,7 +84,7 @@ bool parse_linefeed(struct parse_ctx *ctx)
bool parse_symbol(struct parse_ctx *ctx, enum token_symbol sym) bool parse_symbol(struct parse_ctx *ctx, enum token_symbol sym)
{ {
struct lex_token *tok = peek_token(ctx, DEFAULT_LEX_FLAGS); struct lex_token *tok = peek_token(ctx);
if (!tok) { if (!tok) {
return false; return false;
} }
@@ -101,7 +103,7 @@ bool parse_symbol(struct parse_ctx *ctx, enum token_symbol sym)
bool parse_keyword(struct parse_ctx *ctx, enum token_keyword kw) bool parse_keyword(struct parse_ctx *ctx, enum token_keyword kw)
{ {
struct lex_token *tok = peek_token(ctx, DEFAULT_LEX_FLAGS); struct lex_token *tok = peek_token(ctx);
if (!tok) { if (!tok) {
return false; return false;
} }
@@ -120,7 +122,7 @@ bool parse_keyword(struct parse_ctx *ctx, enum token_keyword kw)
bool parse_int(struct parse_ctx *ctx, long long *out) bool parse_int(struct parse_ctx *ctx, long long *out)
{ {
struct lex_token *tok = peek_token(ctx, DEFAULT_LEX_FLAGS); struct lex_token *tok = peek_token(ctx);
if (!tok) { if (!tok) {
return false; return false;
} }