added variables
This commit is contained in:
parent
603a06ec39
commit
3d6b2cbda5
13 changed files with 368 additions and 43 deletions
4
Makefile
4
Makefile
|
@ -2,8 +2,8 @@ make: trie $(wildcard src/*.c)
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
gcc src/*.c -Wall -Wextra -pedantic -ggdb -o bin/sysh
|
gcc src/*.c -Wall -Wextra -pedantic -ggdb -o bin/sysh
|
||||||
|
|
||||||
trie: triegen.py commands
|
trie: gen/triegen.py gen/commands
|
||||||
python triegen.py commands src/trie.c
|
python gen/triegen.py gen/commands gen/syscalls_x86_64 src/trie.c
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f src/trie.c
|
rm -f src/trie.c
|
||||||
|
|
5
examples/cat.sysh
Normal file
5
examples/cat.sysh
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.set $buf { .alloc 1024 }
|
||||||
|
.set $read { read 0 $buf 1024 }
|
||||||
|
write 1 $buf $read
|
||||||
|
.free $buf
|
||||||
|
|
1
examples/helloworld.sysh
Normal file
1
examples/helloworld.sysh
Normal file
|
@ -0,0 +1 @@
|
||||||
|
write 1 "Hello, world!\n" 14
|
10
gen/commands
Normal file
10
gen/commands
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
.alloc C_ALLOC
|
||||||
|
.realloc C_REALLOC
|
||||||
|
.free C_FREE
|
||||||
|
.set C_SET
|
||||||
|
.cpy C_CPY
|
||||||
|
.deref C_DEREF
|
||||||
|
.strerror C_STRERROR
|
||||||
|
.if C_IF
|
||||||
|
.while C_WHILE
|
||||||
|
.for C_FOR
|
|
@ -9,17 +9,18 @@ if len(sys.argv) < 3:
|
||||||
print("Not enough arguments. Usage: triegen.py <input> <output>")
|
print("Not enough arguments. Usage: triegen.py <input> <output>")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
input_file = sys.argv[1]
|
output_file = sys.argv[len(sys.argv) - 1]
|
||||||
output_file = sys.argv[2]
|
|
||||||
|
|
||||||
with open(input_file, 'r') as f:
|
data = []
|
||||||
data = [re.split('\s+', l.strip()) for l in f.read().split('\n') if len(l.strip()) > 0]
|
for input_file in sys.argv[1:-1]:
|
||||||
|
with open(input_file, 'r') as f:
|
||||||
|
data += [re.split('\s+', l.strip()) for l in f.read().split('\n') if len(l.strip()) > 0]
|
||||||
|
|
||||||
trie = {}
|
trie = {}
|
||||||
|
|
||||||
for line in data:
|
for line in data:
|
||||||
key = line[0] + '\0'
|
key = line[0] + '\0'
|
||||||
val = int(line[1])
|
val = line[1]
|
||||||
trie_local = trie
|
trie_local = trie
|
||||||
for c in key:
|
for c in key:
|
||||||
if c == '\0':
|
if c == '\0':
|
||||||
|
@ -67,7 +68,7 @@ with open(output_file, 'w') as f:
|
||||||
f.write("#include <string.h>\n")
|
f.write("#include <string.h>\n")
|
||||||
f.write("#include \"trie.h\"\n\n")
|
f.write("#include \"trie.h\"\n\n")
|
||||||
f.write("/* auto-generated by triegen.py */\n\n")
|
f.write("/* auto-generated by triegen.py */\n\n")
|
||||||
f.write("int trie_get(const char* key) {\n ")
|
f.write("long trie_get(const char* key) {\n ")
|
||||||
write_trie(f, trie, 0)
|
write_trie(f, trie, 0)
|
||||||
f.write(" return -1;\n}\n")
|
f.write(" return -1;\n}\n")
|
||||||
|
|
148
src/eval.c
148
src/eval.c
|
@ -3,34 +3,67 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
|
#include "hashmap.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
|
#include "trie.h"
|
||||||
|
|
||||||
static long eval_syscall(Line* line) {
|
#define LOGERROR(msg) fprintf(stderr, "sysh: " msg ## "\n")
|
||||||
|
|
||||||
|
static void log_error(const char* format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
fprintf(stderr, "sysh: ");
|
||||||
|
vfprintf(stderr, format, args);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eval_arg(Argument arg, long* result, bool* cloned, Hashmap* vars) {
|
||||||
|
if(arg.type == ARG_NUM) {
|
||||||
|
*result = arg.as.num;
|
||||||
|
if(cloned) *cloned = false;
|
||||||
|
return true;
|
||||||
|
} else if(arg.type == ARG_STR && cloned != NULL) {
|
||||||
|
int len = strlen(arg.as.str);
|
||||||
|
char* buf = malloc(len + 1);
|
||||||
|
strcpy(buf, arg.as.str);
|
||||||
|
*result = (long)buf;
|
||||||
|
*cloned = true;
|
||||||
|
return true;
|
||||||
|
} else if(arg.type == ARG_BLOCK) {
|
||||||
|
*result = eval_block(&arg.as.block, vars);
|
||||||
|
if(cloned) *cloned = false;
|
||||||
|
return true;
|
||||||
|
} else if(arg.type == ARG_VAR) {
|
||||||
|
if(hashmap_get(vars, arg.as.str, result)) {
|
||||||
|
if(cloned) *cloned = false;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long eval_syscall(Line* line, Hashmap* vars) {
|
||||||
if(line->len > 6) {
|
if(line->len > 6) {
|
||||||
fprintf(stderr, "sysh: too many args for syscall\n");
|
log_error("too many arguments for syscall: got %d", line->len);
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
long args[6] = {0,0,0,0,0,0};
|
long args[6] = {0,0,0,0,0,0};
|
||||||
bool cloned[6] = {0,0,0,0,0,0};
|
bool cloned[6] = {0,0,0,0,0,0};
|
||||||
for(int i = 0; i < line->len; i++) {
|
for(int i = 0; i < line->len; i++) {
|
||||||
Argument arg = line->args[i];
|
Argument arg = line->args[i];
|
||||||
if(arg.type == ARG_NUM) {
|
if(!eval_arg(arg, &args[i], &cloned[i], vars)) {
|
||||||
args[i] = arg.as.num;
|
|
||||||
} else if(arg.type == ARG_STR) {
|
|
||||||
int len = strlen(arg.as.str);
|
|
||||||
char* buf = malloc(len + 1);
|
|
||||||
strcpy(buf, arg.as.str);
|
|
||||||
args[i] = (long)buf;
|
|
||||||
cloned[i] = true;
|
|
||||||
} else {
|
|
||||||
for(int j = 0; j < line->len; j++) {
|
for(int j = 0; j < line->len; j++) {
|
||||||
if(cloned[j]) free((void*)args[j]);
|
if(cloned[j]) free((void*)args[j]);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "sysh: invalid arg type\n");
|
log_error("bad argument to syscall");
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long result = syscall(line->id, args[0], args[1], args[2], args[3], args[4], args[5]);
|
long result = syscall(line->id, args[0], args[1], args[2], args[3], args[4], args[5]);
|
||||||
|
@ -40,24 +73,93 @@ static long eval_syscall(Line* line) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long eval_line(Line* line) {
|
static long eval_alloc(Line* line, Hashmap* vars) {
|
||||||
if(line->id >= 0) {
|
if(line->len != 1) {
|
||||||
return eval_syscall(line);
|
log_error(".alloc expected 1 arg, got %d", line->len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
long val;
|
||||||
|
if(!eval_arg(line->args[0], &val, NULL, vars)) {
|
||||||
|
log_error("bad argument to .alloc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (long)malloc(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long eval_realloc(Line* line, Hashmap* vars) {
|
||||||
|
if(line->len != 2) {
|
||||||
|
log_error(".realloc expected 2 args, got %d", line->len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
long val1;
|
||||||
|
long val2;
|
||||||
|
if(!eval_arg(line->args[0], &val1, NULL, vars)) {
|
||||||
|
log_error("bad argument to .realloc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(!eval_arg(line->args[1], &val2, NULL, vars)) {
|
||||||
|
log_error("bad argument to .realloc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (long)realloc((void*)val1, val2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long eval_free(Line* line, Hashmap* vars) {
|
||||||
|
if(line->len != 1) {
|
||||||
|
log_error(".free expected 1 args, got %d", line->len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
long val;
|
||||||
|
if(!eval_arg(line->args[0], &val, NULL, vars)) {
|
||||||
|
log_error("bad argument to .free");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free((void*)val);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long eval_set(Line* line, Hashmap* vars) {
|
||||||
|
if(line->len < 0 || line->len > 2) {
|
||||||
|
log_error(".set expected 1 or 2 args, got %d", line->len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(line->args[0].type != ARG_VAR) {
|
||||||
|
log_error("bad argument to .set");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(line->len == 2) {
|
||||||
|
long val;
|
||||||
|
bool cloned;
|
||||||
|
if(!eval_arg(line->args[1], &val, &cloned, vars)) {
|
||||||
|
log_error("bad argument to .set");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
hashmap_add(vars, strdup(line->args[0].as.str), val);
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
hashmap_remove(vars, line->args[0].as.str);
|
||||||
return 0;
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long eval_line(Line* line, Hashmap* vars) {
|
||||||
|
if(line->id >= 0) {
|
||||||
|
return eval_syscall(line, vars);
|
||||||
|
} else switch(line->id) {
|
||||||
|
case C_ALLOC: return eval_alloc(line, vars);
|
||||||
|
case C_REALLOC: return eval_realloc(line, vars);
|
||||||
|
case C_FREE: return eval_free(line, vars);
|
||||||
|
case C_SET: return eval_set(line, vars);
|
||||||
|
default: return 0; // unreachable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long eval_block(Block* block, Hashmap* vars) {
|
||||||
long eval_block(Block* block) {
|
|
||||||
long result = 0;
|
long result = 0;
|
||||||
for(int i = 0; i < block->len; i++) {
|
for(int i = 0; i < block->len; i++) {
|
||||||
result = eval_line(&block->lines[i]);
|
result = eval_line(&block->lines[i], vars);
|
||||||
if(errno > 0) {
|
if(errno > 0) {
|
||||||
fprintf(stderr, "E%d: %s\n", errno, strerror(errno));
|
fprintf(stderr, "E%d: %s\n", errno, strerror(errno));
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "hashmap.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
long eval_block(Block* block);
|
long eval_block(Block* block, Hashmap* vars);
|
||||||
|
|
107
src/hashmap.c
Normal file
107
src/hashmap.c
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hashmap.h"
|
||||||
|
|
||||||
|
static uint32_t hash_string(const char* key) {
|
||||||
|
uint32_t hash = 2166136261u;
|
||||||
|
while(*key != '\0') {
|
||||||
|
hash ^= (uint8_t)(*key);
|
||||||
|
hash *= 16777619;
|
||||||
|
key++;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashmap_init(Hashmap* hashmap) {
|
||||||
|
hashmap->len = 0;
|
||||||
|
hashmap->capacity = 0;
|
||||||
|
hashmap->entries = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashmap_free(Hashmap* hashmap) {
|
||||||
|
for(int i = 0; i < hashmap->capacity; i++) {
|
||||||
|
Entry e = hashmap->entries[i];
|
||||||
|
if(e.key != NULL) free((char*)e.key);
|
||||||
|
}
|
||||||
|
free(hashmap->entries);
|
||||||
|
hashmap_init(hashmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Entry* hashmap_find(Entry* entries, int capacity, const char* key) {
|
||||||
|
uint32_t index = hash_string(key) % capacity;
|
||||||
|
Entry* tombstone = NULL;
|
||||||
|
while(true) {
|
||||||
|
Entry* entry = &entries[index];
|
||||||
|
if(entry->key == NULL) {
|
||||||
|
if(entry->value == 1) {
|
||||||
|
if(tombstone == NULL) tombstone = entry;
|
||||||
|
} else {
|
||||||
|
return (tombstone == NULL) ? entry : tombstone;
|
||||||
|
}
|
||||||
|
} else if(strcmp(entry->key, key) == 0) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hashmap_grow(Hashmap* map, int capacity) {
|
||||||
|
Entry* entries = malloc(capacity * sizeof(Entry));
|
||||||
|
for(int i = 0; i < capacity; i++) {
|
||||||
|
entries[i].key = NULL;
|
||||||
|
entries[i].value = 0;
|
||||||
|
}
|
||||||
|
map->len = 0;
|
||||||
|
for(int i = 0; i < map->capacity; i++) {
|
||||||
|
Entry* entry = &map->entries[i];
|
||||||
|
if(entry->key == NULL) continue;
|
||||||
|
|
||||||
|
Entry* dest = hashmap_find(entries, capacity, entry->key);
|
||||||
|
dest->key = entry->key;
|
||||||
|
dest->value = entry->value;
|
||||||
|
map->len++;
|
||||||
|
}
|
||||||
|
free(map->entries);
|
||||||
|
|
||||||
|
map->entries = entries;
|
||||||
|
map->capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hashmap_get(Hashmap* hashmap, const char* key, long* value) {
|
||||||
|
if(hashmap->len == 0) return false;
|
||||||
|
|
||||||
|
Entry* e = hashmap_find(hashmap->entries, hashmap->capacity, key);
|
||||||
|
if(e->key == NULL) return false;
|
||||||
|
|
||||||
|
*value = e->value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hashmap_add(Hashmap* hashmap, char* key, long value) {
|
||||||
|
if(hashmap->len + 1 > hashmap->capacity * TABLE_MAX_LOAD) {
|
||||||
|
int capacity = (hashmap->capacity == 0 ? 8 : (2 * hashmap->capacity));
|
||||||
|
hashmap_grow(hashmap, capacity);
|
||||||
|
}
|
||||||
|
Entry* e = hashmap_find(hashmap->entries, hashmap->capacity, key);
|
||||||
|
bool new_key = e->key == NULL;
|
||||||
|
if(new_key) {
|
||||||
|
hashmap->len++;
|
||||||
|
}
|
||||||
|
e->key = key;
|
||||||
|
e->value = value;
|
||||||
|
return new_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hashmap_remove(Hashmap* hashmap, const char* key) {
|
||||||
|
if(hashmap->len == 0) return false;
|
||||||
|
|
||||||
|
Entry* e = hashmap_find(hashmap->entries, hashmap->capacity, key);
|
||||||
|
if(e->key == NULL) return false;
|
||||||
|
|
||||||
|
e->key = NULL;
|
||||||
|
e->value = 1;
|
||||||
|
return true;
|
||||||
|
}
|
23
src/hashmap.h
Normal file
23
src/hashmap.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define TABLE_MAX_LOAD 0.75
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* key;
|
||||||
|
long value;
|
||||||
|
} Entry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int len;
|
||||||
|
int capacity;
|
||||||
|
Entry* entries;
|
||||||
|
} Hashmap;
|
||||||
|
|
||||||
|
void hashmap_init(Hashmap* hashmap);
|
||||||
|
void hashmap_free(Hashmap* hashmap);
|
||||||
|
|
||||||
|
bool hashmap_add(Hashmap* hashmap, char* key, long value);
|
||||||
|
bool hashmap_get(Hashmap* hashmap, const char* key, long* value);
|
||||||
|
bool hashmap_remove(Hashmap* hashmap, const char* key);
|
||||||
|
|
54
src/main.c
54
src/main.c
|
@ -1,9 +1,12 @@
|
||||||
|
#include <errno.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
|
#include "hashmap.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
|
|
||||||
|
@ -11,9 +14,11 @@
|
||||||
#define PROMPT "[%ld]sysh$ "
|
#define PROMPT "[%ld]sysh$ "
|
||||||
#define EPROMPT "[E]sysh$ "
|
#define EPROMPT "[E]sysh$ "
|
||||||
|
|
||||||
void repl() {
|
static long repl() {
|
||||||
char buf[LINE_LEN];
|
char buf[LINE_LEN];
|
||||||
printf(PROMPT, 0L);
|
printf(PROMPT, 0L);
|
||||||
|
Hashmap vars;
|
||||||
|
hashmap_init(&vars);
|
||||||
while(fgets(buf, LINE_LEN, stdin)) {
|
while(fgets(buf, LINE_LEN, stdin)) {
|
||||||
Scanner sc = init_scanner(buf);
|
Scanner sc = init_scanner(buf);
|
||||||
BlockResult br = parse(&sc);
|
BlockResult br = parse(&sc);
|
||||||
|
@ -21,14 +26,51 @@ void repl() {
|
||||||
printf("sysh: %s\n", br.as.err);
|
printf("sysh: %s\n", br.as.err);
|
||||||
printf(EPROMPT);
|
printf(EPROMPT);
|
||||||
} else if(br.as.ok.len > 0) {
|
} else if(br.as.ok.len > 0) {
|
||||||
long result = eval_block(&br.as.ok);
|
long result = eval_block(&br.as.ok, &vars);
|
||||||
printf(PROMPT, result);
|
printf(PROMPT, result);
|
||||||
block_free(&br.as.ok);
|
block_free(&br.as.ok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
hashmap_free(&vars);
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
repl();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long run_file(const char* name) {
|
||||||
|
FILE* file = fopen(name, "r");
|
||||||
|
if(file == NULL) {
|
||||||
|
fprintf(stderr, "%s\n", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
long fsize = ftell(file);
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
|
||||||
|
char* buf = malloc(fsize + 1);
|
||||||
|
fread(buf, fsize, 1, file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
buf[fsize] = '\0';
|
||||||
|
|
||||||
|
Hashmap vars;
|
||||||
|
hashmap_init(&vars);
|
||||||
|
Scanner sc = init_scanner(buf);
|
||||||
|
BlockResult br = parse(&sc);
|
||||||
|
if(!br.is_ok) {
|
||||||
|
printf("sysh: %s\n", br.as.err);
|
||||||
|
} else if(br.as.ok.len > 0) {
|
||||||
|
eval_block(&br.as.ok, &vars);
|
||||||
|
block_free(&br.as.ok);
|
||||||
|
}
|
||||||
|
hashmap_free(&vars);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char** argv) {
|
||||||
|
if(argc < 1) return 1;
|
||||||
|
if(argc == 1) return repl();
|
||||||
|
if(argc == 2) return run_file(argv[1]);
|
||||||
|
fprintf(stderr, "usage: %s [file]\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
30
src/parser.c
30
src/parser.c
|
@ -65,8 +65,9 @@ void line_free(Line* line) {
|
||||||
free(line->args);
|
free(line->args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BlockResult parse_block(Scanner* sc, bool braced);
|
||||||
|
|
||||||
static LineResult parse_line(Scanner* sc, int id) {
|
static LineResult parse_line(Scanner* sc, int id, bool* brace_end) {
|
||||||
Line line;
|
Line line;
|
||||||
line_init(&line, id);
|
line_init(&line, id);
|
||||||
while(true) {
|
while(true) {
|
||||||
|
@ -74,6 +75,10 @@ static LineResult parse_line(Scanner* sc, int id) {
|
||||||
switch(tok.type) {
|
switch(tok.type) {
|
||||||
case TOK_EOF:
|
case TOK_EOF:
|
||||||
case TOK_EOL:
|
case TOK_EOL:
|
||||||
|
*brace_end = false;
|
||||||
|
return OK(line, LineResult);
|
||||||
|
case TOK_RBRACE:
|
||||||
|
*brace_end = true;
|
||||||
return OK(line, LineResult);
|
return OK(line, LineResult);
|
||||||
case TOK_ERR:
|
case TOK_ERR:
|
||||||
line_free(&line);
|
line_free(&line);
|
||||||
|
@ -90,9 +95,17 @@ static LineResult parse_line(Scanner* sc, int id) {
|
||||||
case TOK_CMD:
|
case TOK_CMD:
|
||||||
line_add(&line, (Argument){.type = ARG_CMD, .as.str = tok.as.str});
|
line_add(&line, (Argument){.type = ARG_CMD, .as.str = tok.as.str});
|
||||||
break;
|
break;
|
||||||
|
case TOK_LBRACE: {
|
||||||
|
BlockResult br = parse_block(sc, true);
|
||||||
|
if(!br.is_ok) {
|
||||||
|
line_free(&line);
|
||||||
|
return ERR(br.as.err, LineResult);
|
||||||
|
}
|
||||||
|
line_add(&line, (Argument){.type = ARG_BLOCK, .as.block = br.as.ok});
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
line_free(&line);
|
line_free(&line);
|
||||||
return ERR("unexpected token", LineResult);
|
return ERR("unexpected token in line: %d", LineResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,16 +131,25 @@ static BlockResult parse_block(Scanner* sc, bool braced) {
|
||||||
block_free(&block);
|
block_free(&block);
|
||||||
return ERR("invalid syscall or command name", BlockResult);
|
return ERR("invalid syscall or command name", BlockResult);
|
||||||
}
|
}
|
||||||
LineResult sr = parse_line(sc, id);
|
bool brace_end;
|
||||||
|
LineResult sr = parse_line(sc, id, &brace_end);
|
||||||
if(!sr.is_ok) {
|
if(!sr.is_ok) {
|
||||||
block_free(&block);
|
block_free(&block);
|
||||||
return ERR(sr.as.err, BlockResult);
|
return ERR(sr.as.err, BlockResult);
|
||||||
}
|
}
|
||||||
|
if(brace_end && !braced) {
|
||||||
|
line_free(&sr.as.ok);
|
||||||
|
block_free(&block);
|
||||||
|
return ERR("unexpected token in block", BlockResult);
|
||||||
|
}
|
||||||
block_add(&block, sr.as.ok);
|
block_add(&block, sr.as.ok);
|
||||||
|
if(brace_end) {
|
||||||
|
return OK(block, BlockResult);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
block_free(&block);
|
block_free(&block);
|
||||||
return ERR("unexpected token", BlockResult);
|
return ERR("unexpected token in block", BlockResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return OK(block, BlockResult);
|
return OK(block, BlockResult);
|
||||||
|
|
13
src/trie.h
13
src/trie.h
|
@ -1,3 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
int trie_get(const char* key);
|
#define C_ALLOC -2
|
||||||
|
#define C_REALLOC -3
|
||||||
|
#define C_FREE -4
|
||||||
|
#define C_SET -5
|
||||||
|
#define C_CPY -6
|
||||||
|
#define C_DEREF -7
|
||||||
|
#define C_STRERROR -8
|
||||||
|
#define C_IF -9
|
||||||
|
#define C_WHILE -10
|
||||||
|
#define C_FOR -11
|
||||||
|
|
||||||
|
long trie_get(const char* key);
|
||||||
|
|
Loading…
Reference in a new issue