2026-05-09 19:00:02 +01:00
|
|
|
#include "../syntax.h"
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
bool peek_statement(struct bshell_parse_ctx *ctx)
|
2026-05-12 22:52:48 +01:00
|
|
|
{
|
|
|
|
|
if (peek_keyword_expr(ctx)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (peek_arith_expr(ctx)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (peek_command(ctx)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
bool parse_statement(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out)
|
2026-05-09 19:00:02 +01:00
|
|
|
{
|
2026-05-12 22:52:48 +01:00
|
|
|
if (!peek_token(ctx)) {
|
|
|
|
|
/* error, or EOF */
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool unknown = true;
|
2026-05-09 19:00:02 +01:00
|
|
|
bool ok = false;
|
2026-05-12 22:52:48 +01:00
|
|
|
if (peek_keyword_expr(ctx)) {
|
|
|
|
|
unknown = false;
|
|
|
|
|
ok = parse_keyword_expr(ctx, out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ok && peek_arith_expr(ctx)) {
|
|
|
|
|
unknown = false;
|
2026-05-25 10:33:29 +01:00
|
|
|
ok = parse_arith_expr(ctx, BSHELL_PRECEDENCE_MINIMUM, out);
|
2026-05-09 19:00:02 +01:00
|
|
|
}
|
2026-05-10 14:19:06 +01:00
|
|
|
|
2026-05-09 21:21:51 +01:00
|
|
|
if (!ok && peek_command(ctx)) {
|
2026-05-12 22:52:48 +01:00
|
|
|
unknown = false;
|
2026-05-09 21:21:51 +01:00
|
|
|
ok = parse_command(ctx, out);
|
|
|
|
|
}
|
2026-05-09 19:00:02 +01:00
|
|
|
|
2026-05-12 22:52:48 +01:00
|
|
|
if (!ok && unknown) {
|
|
|
|
|
report_error(
|
|
|
|
|
ctx,
|
|
|
|
|
"encountered unknown token while parsing statement");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-09 19:00:02 +01:00
|
|
|
return ok;
|
|
|
|
|
}
|
2026-05-12 22:52:48 +01:00
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
static struct bshell_ast_node *convert_single_statement(
|
|
|
|
|
struct bshell_stmt_list_ast_node *list)
|
2026-05-12 22:52:48 +01:00
|
|
|
{
|
|
|
|
|
fx_queue_entry *first_entry = fx_queue_first(&list->n_statements);
|
|
|
|
|
if (!first_entry || fx_queue_next(first_entry)) {
|
2026-05-25 10:33:29 +01:00
|
|
|
return (struct bshell_ast_node *)list;
|
2026-05-12 22:52:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fx_queue_delete(&list->n_statements, first_entry);
|
2026-05-25 10:33:29 +01:00
|
|
|
struct bshell_ast_node *first
|
|
|
|
|
= fx_unbox(struct bshell_ast_node, first_entry, n_entry);
|
|
|
|
|
bshell_ast_node_destroy((struct bshell_ast_node *)list);
|
2026-05-12 22:52:48 +01:00
|
|
|
|
|
|
|
|
return first;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
bool parse_statement_list(struct bshell_parse_ctx *ctx, struct bshell_ast_node **out)
|
2026-05-12 22:52:48 +01:00
|
|
|
{
|
2026-05-25 10:33:29 +01:00
|
|
|
struct bshell_stmt_list_ast_node *stmt_list
|
|
|
|
|
= (struct bshell_stmt_list_ast_node *)bshell_ast_node_create(
|
|
|
|
|
BSHELL_AST_STMT_LIST);
|
2026-05-12 22:52:48 +01:00
|
|
|
|
|
|
|
|
bool ok = true;
|
|
|
|
|
while (ok) {
|
|
|
|
|
parse_linefeed(ctx);
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
struct bshell_ast_node *stmt = NULL;
|
2026-05-12 22:52:48 +01:00
|
|
|
if (!parse_statement(ctx, &stmt)) {
|
|
|
|
|
ok = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fx_queue_push_back(&stmt_list->n_statements, &stmt->n_entry);
|
|
|
|
|
|
2026-05-25 10:33:29 +01:00
|
|
|
if (!parse_symbol(ctx, BSHELL_SYM_SEMICOLON)) {
|
2026-05-12 22:52:48 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ok) {
|
2026-05-25 10:33:29 +01:00
|
|
|
bshell_ast_node_destroy((struct bshell_ast_node *)stmt_list);
|
2026-05-12 22:52:48 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*out = convert_single_statement(stmt_list);
|
|
|
|
|
return true;
|
|
|
|
|
}
|