commit d9d021614d5ee3cc0faf6a9439b01a7c1b92756d from: Omar Polo date: Wed Aug 04 08:48:58 2021 UTC rework args and blocks: use a real stack this solves the limitations and bugs of the previous attempt at using a single global variable. The new code is also easier to read IMHO. commit - c734c0e9abc0f228021c1ca2665da71645da46eb commit + d9d021614d5ee3cc0faf6a9439b01a7c1b92756d blob - 54878d74254435a206ffdb0a0bee0066599691fd blob + bf9bce72ab5ffef4c88153d884ccbe76a81deb17 --- np.y +++ np.y @@ -75,8 +75,6 @@ typedef struct { int lineno; } YYSTYPE; -static struct op base_arg; - %} /* @@ -168,9 +166,9 @@ procname: SYMBOL { ; funcall : procname { - prepare_funcall(&base_arg); + prepare_funcall(); } '(' args optcomma ')' { - $$ = op_funcall($1, &base_arg); + $$ = op_funcall($1); } ; @@ -182,11 +180,16 @@ args : /* empty */ ; proc : PROC SYMBOL { - prepare_proc($2); + prepare_proc(); } '(' args ')' { - proc_setup_body(); + if (!proc_setup_body()) { + yyerror("invalid argument in proc `%s' definition", + $2); + free($2); + YYERROR; + } } '{' optnl block '}' { - proc_done(); + proc_done($2); } ; @@ -206,9 +209,9 @@ massert : /* empty */ ; test : TESTING STRING DIR STRING { - prepare_test($2, $4); + prepare_test(); } '{' optnl block '}' { - test_done(); + test_done($2, $4); } ; blob - 7d2891d503c4e27fb09e1586c812d32c97a85882 blob + 634fa8f34b26c0cd75d093392be51ca17fb75050 --- regress/simple.9ps +++ regress/simple.9ps @@ -3,7 +3,7 @@ proc test() { } testing "dummy" dir "./root" { - # test() + test() assert 5 == 7 assert 7 == 9 assert 8 == 0 blob - a06453a45a642ff63f4cea7bdd9f73c2417edfb5 blob + a0bdeabff52b999ef8f84971713303b65cd1bf56 --- script.c +++ script.c @@ -32,14 +32,9 @@ static struct procs procs = TAILQ_HEAD_INITIALIZER(procs); static struct tests tests = TAILQ_HEAD_INITIALIZER(tests); -static struct proc *curr_proc; -static struct test *curr_test; +static struct opstacks blocks = TAILQ_HEAD_INITIALIZER(blocks); +static struct opstacks args = TAILQ_HEAD_INITIALIZER(args); -static struct op *curr_block; - -static struct op *curr_argv; -static int curr_argc; - #define STACK_HEIGHT 16 static struct value vstack[STACK_HEIGHT]; static int stackh; @@ -47,6 +42,62 @@ static int stackh; static struct value v_false = {.type = V_NUM, .v = {.num = 0}}; static struct value v_true = {.type = V_NUM, .v = {.num = 1}}; +static inline struct opstack * +pushstack(struct opstacks *stack) +{ + struct opstack *ops; + + ops = xcalloc(1, sizeof(*ops)); + TAILQ_INSERT_HEAD(stack, ops, entry); + return ops; +} + +static inline struct opstack * +peek(struct opstacks *stack) +{ + if (TAILQ_EMPTY(stack)) + errx(1, "%s: args underflow", __func__); + + return TAILQ_FIRST(stack); +} + +static inline struct op * +finalize(struct opstacks *stack, int *argc) +{ + struct opstack *ops; + struct op *op; + + if (TAILQ_EMPTY(stack)) + errx(1, "%s: args underflow", __func__); + + ops = peek(stack); + TAILQ_REMOVE(&args, ops, entry); + op = ops->base.next; + + if (argc != NULL) + *argc = ops->counter; + + free(ops); + return op; +} + +static inline void +push(struct opstacks *stack, struct op *op) +{ + struct opstack *ops; + + ops = peek(stack); + if (ops->last == NULL) { + ops->base.next = op; + ops->last = op; + } else { + ops->last->next = op; + ops->last = op; + } + + ops->counter++; +} + void global_set(char *sym, struct op *op) { @@ -373,35 +424,30 @@ eval(struct op *op) } void -prepare_funcall(struct op *base) +prepare_funcall(void) { - if (curr_argv != NULL) - err(1, "can't funcall during funcall"); - - curr_argv = base; - curr_argc = 0; + pushstack(&args); } void push_arg(struct op *op) { - curr_argv->next = op; - curr_argv = op; - curr_argc++; + push(&args, op); } struct op * -op_funcall(struct proc *proc, struct op *base) +op_funcall(struct proc *proc) { - struct op *op; + struct op *op, *argv; + int argc; + argv = finalize(&args, &argc); + op = newop(OP_FUNCALL); op->v.funcall.proc = proc; - op->v.funcall.argv = base->next; - op->v.funcall.argc = curr_argc; + op->v.funcall.argv = argv; + op->v.funcall.argc = argc; - curr_argv = NULL; - return op; } @@ -418,58 +464,66 @@ add_builtin_proc(const char *name, int (*fn)(int)) } void -prepare_proc(char *name) +prepare_proc(void) { - if (curr_proc != NULL) - err(1, "can't recursively create a proc!"); + pushstack(&args); +} - curr_proc = xcalloc(1, sizeof(*curr_proc)); - curr_proc->name = name; - - curr_argv = &curr_proc->tmp_args; - - curr_argv = NULL; - curr_argc = 0; -} - -void +int proc_setup_body(void) { - struct op *next, *op = curr_proc->tmp_args.next; - int i; + struct opstack *argv; + struct op *op; + int i; - i = 0; - while (op != NULL) { + argv = peek(&args); + for (i = 0, op = argv->base.next; op != NULL; i++) { + /* + * TODO: should free the whole list but.., we're gonna + * exit real soon(tm)! + */ if (op->type != OP_VAR) - errx(1, "invalid argument in proc definition: " - "got type %d but want OP_VAR", op->type); - assert(i < curr_argc && curr_argc < MAXWELEM); - curr_proc->args[i] = xstrdup(op->v.var); - next = op->next; - free_op(op); + return 0; } - curr_proc->minargs = curr_argc; + assert(i == argv->counter); + pushstack(&blocks); + return 1; } void -proc_done(void) +proc_done(char *name) { - TAILQ_INSERT_HEAD(&procs, curr_proc, entry); + struct proc *proc; + struct op *op, *next, *argv, *body; + int i, argc; - curr_proc = NULL; + argv = finalize(&args, &argc); + body = finalize(&blocks, NULL); + + proc = xcalloc(1, sizeof(*proc)); + proc->name = name; + proc->minargs = argc; + + for (i = 0, op = argv; i < argc; ++i) { + proc->args[i] = xstrdup(op->v.var); + + next = op->next; + assert(next != NULL); + + free_op(op); + op = next; + } + + proc->body = body; + + TAILQ_INSERT_HEAD(&procs, proc, entry); } void block_push(struct op *op) { - if (curr_block == NULL) { - curr_proc->body = op; - curr_block = op; - } else { - curr_block->next = op; - curr_block = op; - } + push(&blocks, op); } struct proc * @@ -486,23 +540,22 @@ proc_by_name(const char *name) } void -prepare_test(char *name, char *dir) +prepare_test(void) { - assert(curr_test == NULL); - - prepare_proc(xstrdup("")); - - curr_test = xcalloc(1, sizeof(*curr_test)); - curr_test->name = name; - curr_test->dir = dir; - curr_test->proc = curr_proc; + pushstack(&blocks); } void -test_done(void) +test_done(char *name, char *dir) { - TAILQ_INSERT_HEAD(&tests, curr_test, entry); - curr_test = NULL; + struct test *test; + + test = xcalloc(1, sizeof(*test)); + test->name = name; + test->dir = dir; + test->body = finalize(&blocks, NULL); + + TAILQ_INSERT_HEAD(&tests, test, entry); } static int @@ -521,7 +574,7 @@ run_test(struct test *t) puts("====================="); #endif - return eval(t->proc->body); + return eval(t->body); } int blob - ad3c7e7c91c090d190de2c8b416c57a58b6ff21c blob + 0040420c663c6389250d8bc4f6e34cfe2d83d028 --- script.h +++ script.h @@ -82,6 +82,14 @@ struct op { } v; }; +TAILQ_HEAD(opstacks, opstack); +struct opstack { + TAILQ_ENTRY(opstack) entry; + struct op base; + struct op *last; + int counter; +}; + TAILQ_HEAD(procs, proc); struct proc { TAILQ_ENTRY(proc) entry; @@ -89,7 +97,6 @@ struct proc { int minargs; int varargs; char *args[MAXWELEM]; - struct op tmp_args; struct op *body; int (*nativefn)(int); }; @@ -99,7 +106,7 @@ struct test { TAILQ_ENTRY(test) entry; char *name; char *dir; - struct proc *proc; + struct op *body; }; enum { @@ -128,22 +135,22 @@ void pp_block(struct op *); int eval(struct op *); /* funcall */ -void prepare_funcall(struct op *); +void prepare_funcall(void); void push_arg(struct op *); -struct op *op_funcall(struct proc *, struct op *); +struct op *op_funcall(struct proc *); /* proc */ void add_builtin_proc(const char *name, int (*)(int)); -void prepare_proc(char *); +void prepare_proc(void); /* push_arg works on procs too */ -void proc_setup_body(void); -void proc_done(void); +int proc_setup_body(void); +void proc_done(char *name); void block_push(struct op *); struct proc *proc_by_name(const char *); /* testing */ -void prepare_test(char *, char *); -void test_done(void); +void prepare_test(void); +void test_done(char *, char *); /* np.y */ void loadfile(const char *);