Split CE code into multiple files
All checks were successful
Build documentation / build-and-deploy (push) Successful in 2m38s
All checks were successful
Build documentation / build-and-deploy (push) Successful in 2m38s
This commit is contained in:
182
ce/parser.c
Normal file
182
ce/parser.c
Normal file
@@ -0,0 +1,182 @@
|
||||
#include "parser.h"
|
||||
#include "arena_alloc.h"
|
||||
#include "context.h"
|
||||
#include "interp.h"
|
||||
#include "mprintf.h"
|
||||
#include <arena.h>
|
||||
#include <list.h>
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user