sysh/src/parser.c

139 lines
3.7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "parser.h"
#include "scanner.h"
#include "trie.h"
void block_init(Block* b) {
b->len = 0;
b->capacity = 0;
b->lines = NULL;
}
void block_add(Block* b, Line l) {
if(b->capacity <= b->len) {
int new_capacity = (b->capacity == 0 ? 8 : 2*(b->capacity));
b->lines = realloc(b->lines, new_capacity * sizeof(Line));
b->capacity = new_capacity;
}
b->lines[b->len] = l;
b->len++;
}
void block_free(Block* b) {
for(int i = 0; i < b->len; i++) {
line_free(&b->lines[i]);
}
free(b->lines);
block_init(b);
}
void line_init(Line* l, long id) {
l->id = id;
l->len = 0;
l->capacity = 0;
l->args = NULL;
}
void line_add(Line* l, Argument arg) {
if(l->capacity <= l->len) {
int new_capacity = (l->capacity == 0 ? 8 : 2*(l->capacity));
l->args = realloc(l->args, new_capacity * sizeof(Argument));
l->capacity = new_capacity;
}
l->args[l->len] = arg;
l->len++;
}
void line_free(Line* line) {
for(int i = 0; i < line->len; i++) {
switch(line->args[i].type) {
case ARG_BLOCK:
block_free(&line->args[i].as.block);
break;
case ARG_STR:
case ARG_CMD:
case ARG_VAR:
free((char*)line->args[i].as.str);
break;
case ARG_NUM:
break;
}
}
free(line->args);
}
static LineResult parse_line(Scanner* sc, int id) {
Line line;
line_init(&line, id);
while(true) {
Token tok = scanner_next(sc);
switch(tok.type) {
case TOK_EOF:
case TOK_EOL:
return OK(line, LineResult);
case TOK_ERR:
line_free(&line);
return ERR(tok.as.str, LineResult);
case TOK_INT:
line_add(&line, (Argument){.type = ARG_NUM, .as.num = tok.as.num});
break;
case TOK_VAR:
line_add(&line, (Argument){.type = ARG_VAR, .as.str = tok.as.str});
break;
case TOK_STR:
line_add(&line, (Argument){.type = ARG_STR, .as.str = tok.as.str});
break;
case TOK_CMD:
line_add(&line, (Argument){.type = ARG_CMD, .as.str = tok.as.str});
break;
default:
line_free(&line);
return ERR("unexpected token", LineResult);
}
}
}
static BlockResult parse_block(Scanner* sc, bool braced) {
Block block;
block_init(&block);
while(true) {
Token tok = scanner_next(sc);
if((!braced && tok.type == TOK_EOF) || (braced && tok.type == TOK_RBRACE)) {
return OK(block, BlockResult);
}
switch(tok.type) {
case TOK_ERR:
block_free(&block);
return ERR(tok.as.str, BlockResult);
case TOK_EOL:
continue;
case TOK_CMD: {
long id = trie_get(tok.as.str);
token_free(&tok);
if(id == -1) {
block_free(&block);
return ERR("invalid syscall or command name", BlockResult);
}
LineResult sr = parse_line(sc, id);
if(!sr.is_ok) {
block_free(&block);
return ERR(sr.as.err, BlockResult);
}
block_add(&block, sr.as.ok);
} break;
default:
block_free(&block);
return ERR("unexpected token", BlockResult);
}
}
return OK(block, BlockResult);
}
BlockResult parse(Scanner* sc) {
return parse_block(sc, false);
}