#include "parser.h" #include "arena_alloc.h" #include "context.h" #include "interp.h" #include "mprintf.h" #include #include #include static struct parse_rule parse_rules[] = { [TOKEN_CLASS_WORD] = {&word_nud, NULL, PREC_NONE}, [TOKEN_CLASS_OPAREN] = {&oparen_nud, NULL, PREC_NONE}, [TOKEN_CLASS_CPAREN] = {NULL, NULL, PREC_NONE}, [TOKEN_CLASS_SEMICOLON] = {NULL, &semicolon_led, PREC_SEQ}, [TOKEN_CLASS_REDIR] = {NULL, &redir_led, PREC_REDIR}, }; static struct token* get_token (struct list_node_link* link) { if (link == NULL) return NULL; return list_entry (link, struct token, tokens_link); } static struct token* advance (struct parser* parser) { struct token* token = parser->next; if (token != NULL) { parser->current = token; parser->next = get_token (token->tokens_link.next); } else { parser->current = NULL; } return token; } static struct ast_node* parse_precedence (struct parser* parser, int precedence) { struct token* token = advance (parser); if (token == NULL) return NULL; nud_func_t nud = parse_rules[token->class].nud; if (nud == NULL) return NULL; struct ast_node* left = nud (parser, token); while (parser->next && precedence < parse_rules[parser->next->class].precedence) { token = advance (parser); led_func_t led = parse_rules[token->class].led; if (led != NULL) left = led (parser, token, left); } return left; } struct ast_node* word_nud (struct parser* parser, struct token* token) { struct ast_node* node = arena_malloc (&arena, sizeof (*node)); node->class = AST_NODE_CLASS_CMD; node->u.cmd.name = token->buffer; node->u.cmd.arg_count = 0; while (parser->next != NULL && parser->next->class == TOKEN_CLASS_WORD) { struct token* arg = advance (parser); if (node->u.cmd.arg_count < CMD_ARGS_MAX) node->u.cmd.args[node->u.cmd.arg_count++] = arg->buffer; } return node; } struct ast_node* oparen_nud (struct parser* parser, struct token* token) { (void)token; struct ast_node* node = arena_malloc (&arena, sizeof (*node)); node->class = AST_NODE_CLASS_SUBSHELL; node->u.subshell.inner = parse_precedence (parser, PREC_LOWEST); if (parser->next != NULL && parser->next->class == TOKEN_CLASS_CPAREN) advance (parser); return node; } struct ast_node* semicolon_led (struct parser* parser, struct token* token, struct ast_node* left) { (void)token; struct ast_node* node = arena_malloc (&arena, sizeof (*node)); node->class = AST_NODE_CLASS_SEQ; node->u.seq.left = left; node->u.seq.right = parse_precedence (parser, PREC_SEQ); return node; } struct ast_node* redir_led (struct parser* parser, struct token* token, struct ast_node* left) { (void)token; struct ast_node* node = arena_malloc (&arena, sizeof (*node)); node->class = AST_NODE_CLASS_REDIR; node->u.redir.source = left; struct token* next_token = advance (parser); if (next_token != NULL && next_token->class == TOKEN_CLASS_WORD) node->u.redir.file_path = next_token->buffer; return node; } void tokenize (struct list_node_link** tokens, const char* text) { const char* p = text; while (*p) { if (isspace (*p)) { p++; continue; } if (*p == '(' || *p == ')' || *p == ';' || *p == '>') { struct token* token = arena_malloc (&arena, sizeof (*token)); memset (token, 0, sizeof (*token)); token->buffer[0] = *p; if (*p == '(') token->class = TOKEN_CLASS_OPAREN; else if (*p == ')') token->class = TOKEN_CLASS_CPAREN; else if (*p == ';') token->class = TOKEN_CLASS_SEMICOLON; else if (*p == '>') token->class = TOKEN_CLASS_REDIR; list_append (*tokens, &token->tokens_link); p++; continue; } if (isprint (*p)) { struct token* token = arena_malloc (&arena, sizeof (*token)); memset (token, 0, sizeof (*token)); size_t i = 0; while (*p && !isspace (*p) && *p != '(' && *p != ')' && *p != ';' && *p != '>') { if (i < TOKEN_MAX - 1) token->buffer[i++] = *p; p++; } token->class = TOKEN_CLASS_WORD; list_append (*tokens, &token->tokens_link); continue; } mprintf ("ERROR unknown character '%c'\n", *p); p++; } } void parse_and_execute (struct list_node_link* tokens) { struct parser parser; parser.current = NULL; parser.next = get_token (tokens); while (parser.next != NULL) { struct ast_node* root = parse_precedence (&parser, PREC_NONE); if (root != NULL) { struct context context = {0}; execute (root, &context); if (context.strbuf.items != NULL) mprintf ("%.*s", (int)context.strbuf.count, context.strbuf.items); } } }