###### Parser: header
## macros
+ struct parse_context;
## ast
struct parse_context {
struct token_config config;
fprintf(stderr, "oceani: type error in program - not running.\n");
exit(1);
}
- interp_prog(context.prog, argv+optind+1);
+ interp_prog(&context, context.prog, argv+optind+1);
}
free_exec(context.prog);
outside the if, the variables in the different branches are distinct
and can be of different types.
-Determining the types of all variables early is important for
-processing command line arguments. These can be assigned to any of
-several types of variable, but we must first know the correct type so
-any required conversion can happen. If a variable is associated with
-a command line argument but no type can be interpreted (e.g. the
-variable is only ever used in a `print` statement), then the type is
-set to 'string'.
-
Undeclared names may only appear in "use" statements and "case" expressions.
These names are given a type of "label" and a unique value.
This allows them to fill the role of a name in an enumerated type, which
### Types
Values come in a wide range of types, with more likely to be added.
-Each type needs to be able to parse and print its own values (for
-convenience at least) as well as to compare two values, at least for
-equality and possibly for order. For now, values might need to be
-duplicated and freed, though eventually such manipulations will be
-better integrated into the language.
+Each type needs to be able to print its own values (for convenience at
+least) as well as to compare two values, at least for equality and
+possibly for order. For now, values might need to be duplicated and
+freed, though eventually such manipulations will be better integrated
+into the language.
Rather than requiring every numeric type to support all numeric
operations (add, multiple, etc), we allow types to be able to present
struct type *next;
int size, align;
void (*init)(struct type *type, struct value *val);
- int (*parse)(struct type *type, char *str, struct value *val);
+ void (*prepare_type)(struct parse_context *c, struct type *type, int parse_time);
void (*print)(struct type *type, struct value *val);
void (*print_type)(struct type *type, FILE *f);
int (*cmp_order)(struct type *t1, struct type *t2,
printf("*Unknown*"); // NOTEST
}
- static int parse_value(struct type *type, char *arg,
- struct value *val)
- {
- if (type && type->parse)
- return type->parse(type, arg, val);
- return 0; // NOTEST
- }
-
- static struct value *val_alloc(struct type *t, struct value *init)
+ static struct value *val_alloc(struct parse_context *c, struct type *t,
+ struct value *init)
{
struct value *ret;
- if (!t->size)
- val_init(t, NULL);
+ if (t->prepare_type)
+ t->prepare_type(c, t, 0);
+
ret = calloc(1, t->size);
if (init)
memcpy(ret, init, t->size);
static int value_cmp(struct type *tl, struct type *tr,
struct value *left, struct value *right);
static void print_value(struct type *type, struct value *v);
- static int parse_value(struct type *type, char *arg, struct value *val);
###### free context types
return require == have;
}
-When assigning command line arguments to variables, we need to be able
-to parse each type from a string.
-
###### includes
#include <gmp.h>
#include "parse_string.h"
}
}
- static int _parse_value(struct type *type, char *arg, struct value *val)
- {
- struct text tx;
- int neg = 0;
- char tail[3] = "";
-
- switch(type->vtype) {
- case Vlabel: // NOTEST
- case Vnone: // NOTEST
- return 0; // NOTEST
- case Vstr:
- val->str.len = strlen(arg);
- val->str.txt = malloc(val->str.len);
- memcpy(val->str.txt, arg, val->str.len);
- break;
- case Vnum:
- if (*arg == '-') {
- neg = 1;
- arg++;
- }
- tx.txt = arg; tx.len = strlen(tx.txt);
- if (number_parse(val->num, tail, tx) == 0)
- mpq_init(val->num);
- else if (neg)
- mpq_neg(val->num, val->num);
- if (tail[0]) {
- printf("Unsupported suffix: %s\n", arg);
- return 0;
- }
- break;
- case Vbool:
- if (strcasecmp(arg, "true") == 0 ||
- strcmp(arg, "1") == 0)
- val->bool = 1;
- else if (strcasecmp(arg, "false") == 0 ||
- strcmp(arg, "0") == 0)
- val->bool = 0;
- else {
- printf("Bad bool: %s\n", arg);
- return 0;
- }
- break;
- }
- return 1;
- }
-
static void _free_value(struct type *type, struct value *v);
static struct type base_prototype = {
.init = _val_init,
- .parse = _parse_value,
.print = _print_value,
.cmp_order = _value_cmp,
.cmp_eq = _value_cmp,
struct value rval, *lval;
};
- static struct lrval _interp_exec(struct exec *e);
+ static struct lrval _interp_exec(struct parse_context *c, struct exec *e);
- static struct value interp_exec(struct exec *e, struct type **typeret)
+ static struct value interp_exec(struct parse_context *c, struct exec *e,
+ struct type **typeret)
{
- struct lrval ret = _interp_exec(e);
+ struct lrval ret = _interp_exec(c, e);
if (!ret.type) abort();
if (typeret)
return ret.rval;
}
- static struct value *linterp_exec(struct exec *e, struct type **typeret)
+ static struct value *linterp_exec(struct parse_context *c, struct exec *e,
+ struct type **typeret)
{
- struct lrval ret = _interp_exec(e);
+ struct lrval ret = _interp_exec(c, e);
- if (typeret)
+ if (ret.lval)
*typeret = ret.type;
+ else
+ free_value(ret.type, &ret.rval);
return ret.lval;
}
- static struct lrval _interp_exec(struct exec *e)
+ static struct lrval _interp_exec(struct parse_context *c, struct exec *e)
{
struct lrval ret;
struct value rv = {}, *lrv = NULL;
Thus far we have arrays and structs.
-Some complex types need do not exist in a name table, so they are kept
-on a linked list in the context (`anon_typelist`). This allows them to
-be freed when parsing is complete.
-
#### Arrays
Arrays can be declared by giving a size and a type, as `[size]type' so
a "`copy`" primitive will eventually be define which can be used to
make a copy of an array with controllable recursive depth.
+For now we have two sorts of array, those with fixed size either because
+it is given as a literal number or because it is a struct member (which
+cannot have a runtime-changing size), and those with a size that is
+determined at runtime - local variables with a const size. The former
+have their size calculated at parse time, the latter at run time.
+
+For the latter type, the `size` field of the type is the size of a
+pointer, and the array is reallocated every time it comes into scope.
+
+We differentiate struct fields with a const size from local variables
+with a const size by whether they are prepared at parse time or not.
+
###### type union fields
struct {
- int size;
+ short size;
+ short static_size;
struct variable *vsize;
struct type *member;
} array;
###### value union fields
- void *array;
+ void *array; // used if not static_size
###### value functions
- static void array_init(struct type *type, struct value *val)
+ static void array_prepare_type(struct parse_context *c, struct type *type,
+ int parse_time)
{
- int i;
+ mpz_t q;
+ if (!type->array.vsize || type->array.static_size)
+ return;
- if (type->array.vsize) {
- mpz_t q;
- mpz_init(q);
- mpz_tdiv_q(q, mpq_numref(type->array.vsize->val->num),
- mpq_denref(type->array.vsize->val->num));
- type->array.size = mpz_get_si(q);
- mpz_clear(q);
+ mpz_init(q);
+ mpz_tdiv_q(q, mpq_numref(type->array.vsize->val->num),
+ mpq_denref(type->array.vsize->val->num));
+ type->array.size = mpz_get_si(q);
+ mpz_clear(q);
+
+ if (parse_time) {
+ type->array.static_size = 1;
+ type->size = type->array.size * type->array.member->size;
+ type->align = type->array.member->align;
}
- type->size = type->array.size * type->array.member->size;
- type->align = type->array.member->align;
+ }
+
+ static void array_init(struct type *type, struct value *val)
+ {
+ int i;
+ void *ptr = val->ptr;
if (!val)
- return;
+ return;
+ if (!type->array.static_size) {
+ val->array = calloc(type->array.size,
+ type->array.member->size);
+ ptr = val->array;
+ }
for (i = 0; i < type->array.size; i++) {
struct value *v;
- v = (void*)val->ptr + i * type->array.member->size;
+ v = (void*)ptr + i * type->array.member->size;
val_init(type->array.member, v);
}
}
static void array_free(struct type *type, struct value *val)
{
int i;
+ void *ptr = val->ptr;
+ if (!type->array.static_size)
+ ptr = val->array;
for (i = 0; i < type->array.size; i++) {
struct value *v;
- v = (void*)val->ptr + i * type->array.member->size;
+ v = (void*)ptr + i * type->array.member->size;
free_value(type->array.member, v);
}
+ if (!type->array.static_size)
+ free(ptr);
}
static int array_compat(struct type *require, struct type *have)
static struct type array_prototype = {
.init = array_init,
+ .prepare_type = array_prepare_type,
.print_type = array_print_type,
.compat = array_compat,
.free = array_free,
+ .size = sizeof(void*),
+ .align = sizeof(void*),
};
+###### declare terminals
+ $TERM [ ]
+
###### type grammar
- | [ NUMBER ] Type ${
- $0 = calloc(1, sizeof(struct type));
- *($0) = array_prototype;
- $0->array.member = $<4;
- $0->array.vsize = NULL;
- {
+ | [ NUMBER ] Type ${ {
char tail[3];
mpq_t num;
+ struct text noname = { "", 0 };
+ struct type *t;
+
+ $0 = t = add_type(c, noname, &array_prototype);
+ t->array.member = $<4;
+ t->array.vsize = NULL;
if (number_parse(num, tail, $2.txt) == 0)
tok_err(c, "error: unrecognised number", &$2);
else if (tail[0])
tok_err(c, "error: unsupported number suffix", &$2);
else {
- $0->array.size = mpz_get_ui(mpq_numref(num));
+ t->array.size = mpz_get_ui(mpq_numref(num));
if (mpz_cmp_ui(mpq_denref(num), 1) != 0) {
tok_err(c, "error: array size must be an integer",
&$2);
&$2);
mpq_clear(num);
}
- $0->next = c->anon_typelist;
- c->anon_typelist = $0;
- }
- }$
+ t->array.static_size = 1;
+ t->size = t->array.size * t->array.member->size;
+ t->align = t->array.member->align;
+ } }$
| [ IDENTIFIER ] Type ${ {
struct variable *v = var_ref(c, $2.txt);
+ struct text noname = { "", 0 };
if (!v)
tok_err(c, "error: name undeclared", &$2);
else if (!v->constant)
tok_err(c, "error: array size must be a constant", &$2);
- $0 = calloc(1, sizeof(struct type));
- *($0) = array_prototype;
+ $0 = add_type(c, noname, &array_prototype);
$0->array.member = $<4;
$0->array.size = 0;
$0->array.vsize = v;
- $0->next = c->anon_typelist;
- c->anon_typelist = $0;
} }$
-###### parse context
-
- struct type *anon_typelist;
-
-###### free context types
-
- while (context.anon_typelist) {
- struct type *t = context.anon_typelist;
-
- context.anon_typelist = t->next;
- free(t);
- }
-
###### Binode types
Index,
case Index: {
mpz_t q;
long i;
+ void *ptr;
- lleft = linterp_exec(b->left, <ype);
- right = interp_exec(b->right, &rtype);
+ lleft = linterp_exec(c, b->left, <ype);
+ right = interp_exec(c, b->right, &rtype);
mpz_init(q);
mpz_tdiv_q(q, mpq_numref(right.num), mpq_denref(right.num));
i = mpz_get_si(q);
mpz_clear(q);
+ if (ltype->array.static_size)
+ ptr = lleft;
+ else
+ ptr = *(void**)lleft;
rvtype = ltype->array.member;
if (i >= 0 && i < ltype->array.size)
- lrv = (void*)lleft + i * rvtype->size;
+ lrv = ptr + i * rvtype->size;
else
val_init(ltype->array.member, &rv);
ltype = NULL;
for (i = 0; i < type->structure.nfields; i++) {
struct value *v;
v = (void*) val->ptr + type->structure.fields[i].offset;
- val_init(type->structure.fields[i].type, v);
+ if (type->structure.fields[i].init)
+ dup_value(type->structure.fields[i].type,
+ type->structure.fields[i].init,
+ v);
+ else
+ val_init(type->structure.fields[i].type, v);
}
}
free(e);
break;
+###### declare terminals
+ $TERM struct .
+
###### variable grammar
| Variable . IDENTIFIER ${ {
{
struct fieldref *f = cast(fieldref, e);
struct type *ltype;
- struct value *lleft = linterp_exec(f->left, <ype);
+ struct value *lleft = linterp_exec(c, f->left, <ype);
lrv = (void*)lleft->ptr + ltype->structure.fields[f->index].offset;
rvtype = ltype->structure.fields[f->index].type;
break;
if (!ok)
c->parse_error = 1;
else {
- struct value vl = interp_exec($5, NULL);
- $0->f.init = val_alloc($0->f.type, &vl);
+ struct value vl = interp_exec(c, $5, NULL);
+ $0->f.init = val_alloc(c, $0->f.type, &vl);
}
} }$
| IDENTIFIER : Type ${
$0 = calloc(1, sizeof(struct fieldlist));
$0->f.name = $1.txt;
$0->f.type = $<3;
- $0->f.init = val_alloc($0->f.type, NULL);
+ if ($0->f.type->prepare_type)
+ $0->f.type->prepare_type(c, $0->f.type, 1);
}$
###### forward decls
###### Grammar
+ $TERM True False
+
$*val
Value -> True ${
$0 = new_val(Tbool, $1);
###### Grammar
+ $TERM : ::
+
$*var
VariableDecl -> IDENTIFIER : ${ {
struct variable *v = var_decl(c, $1.txt);
case CondExpr: {
struct binode *b2 = cast(binode, b->right);
- left = interp_exec(b->left, <ype);
+ left = interp_exec(c, b->left, <ype);
if (left.bool)
- rv = interp_exec(b2->left, &rvtype);
+ rv = interp_exec(c, b2->left, &rvtype);
else
- rv = interp_exec(b2->right, &rvtype);
+ rv = interp_exec(c, b2->right, &rvtype);
}
break;
###### interp binode cases
case And:
- rv = interp_exec(b->left, &rvtype);
- right = interp_exec(b->right, &rtype);
+ rv = interp_exec(c, b->left, &rvtype);
+ right = interp_exec(c, b->right, &rtype);
rv.bool = rv.bool && right.bool;
break;
case AndThen:
- rv = interp_exec(b->left, &rvtype);
+ rv = interp_exec(c, b->left, &rvtype);
if (rv.bool)
- rv = interp_exec(b->right, NULL);
+ rv = interp_exec(c, b->right, NULL);
break;
case Or:
- rv = interp_exec(b->left, &rvtype);
- right = interp_exec(b->right, &rtype);
+ rv = interp_exec(c, b->left, &rvtype);
+ right = interp_exec(c, b->right, &rtype);
rv.bool = rv.bool || right.bool;
break;
case OrElse:
- rv = interp_exec(b->left, &rvtype);
+ rv = interp_exec(c, b->left, &rvtype);
if (!rv.bool)
- rv = interp_exec(b->right, NULL);
+ rv = interp_exec(c, b->right, NULL);
break;
case Not:
- rv = interp_exec(b->right, &rvtype);
+ rv = interp_exec(c, b->right, &rvtype);
rv.bool = !rv.bool;
break;
case NEql:
{
int cmp;
- left = interp_exec(b->left, <ype);
- right = interp_exec(b->right, &rtype);
+ left = interp_exec(c, b->left, <ype);
+ right = interp_exec(c, b->right, &rtype);
cmp = value_cmp(ltype, rtype, &left, &right);
rvtype = Tbool;
switch (b->op) {
### Expressions: The rest
-The remaining expressions with the highest precedence are arithmetic and
-string concatenation. String concatenation (`++`) has the same
-precedence as multiplication and division, but lower than the uniary.
+The remaining expressions with the highest precedence are arithmetic,
+string concatenation, and string conversion. String concatenation
+(`++`) has the same precedence as multiplication and division, but lower
+than the uniary.
+
+String conversion is a temporary feature until I get a better type
+system. `$` is a prefix operator which expects a string and returns
+a number.
`+` and `-` are both infix and prefix operations (where they are
absolute value and negation). These have different operator names.
Times, Divide, Rem,
Concat,
Absolute, Negate,
+ StringConv,
Bracket,
###### expr precedence
$LEFT + - Eop
$LEFT * / % ++ Top
- $LEFT Uop
+ $LEFT Uop $
$TERM ( )
###### expression grammar
Uop -> + ${ $0.op = Absolute; }$
| - ${ $0.op = Negate; }$
+ | $ ${ $0.op = StringConv; }$
Top -> * ${ $0.op = Times; }$
| / ${ $0.op = Divide; }$
if (bracket) printf(")");
break;
case Absolute:
- if (bracket) printf("(");
- printf("+");
- print_exec(b->right, indent, bracket);
- if (bracket) printf(")");
- break;
case Negate:
+ case StringConv:
if (bracket) printf("(");
- printf("-");
+ switch (b->op) {
+ case Absolute: fputs("+", stdout); break;
+ case Negate: fputs("-", stdout); break;
+ case StringConv: fputs("$", stdout); break;
+ default: abort(); // NOTEST
+ } // NOTEST
print_exec(b->right, indent, bracket);
if (bracket) printf(")");
break;
Tstr, rules, type);
return Tstr;
+ case StringConv:
+ /* op must be string, result is number */
+ propagate_types(b->left, c, ok, Tstr, 0);
+ if (!type_compat(type, Tnum, 0))
+ type_err(c,
+ "error: Can only convert string to number, not %1",
+ prog, type, 0, NULL);
+ return Tnum;
+
case Bracket:
return propagate_types(b->right, c, ok, type, 0);
###### interp binode cases
case Plus:
- rv = interp_exec(b->left, &rvtype);
- right = interp_exec(b->right, &rtype);
+ rv = interp_exec(c, b->left, &rvtype);
+ right = interp_exec(c, b->right, &rtype);
mpq_add(rv.num, rv.num, right.num);
break;
case Minus:
- rv = interp_exec(b->left, &rvtype);
- right = interp_exec(b->right, &rtype);
+ rv = interp_exec(c, b->left, &rvtype);
+ right = interp_exec(c, b->right, &rtype);
mpq_sub(rv.num, rv.num, right.num);
break;
case Times:
- rv = interp_exec(b->left, &rvtype);
- right = interp_exec(b->right, &rtype);
+ rv = interp_exec(c, b->left, &rvtype);
+ right = interp_exec(c, b->right, &rtype);
mpq_mul(rv.num, rv.num, right.num);
break;
case Divide:
- rv = interp_exec(b->left, &rvtype);
- right = interp_exec(b->right, &rtype);
+ rv = interp_exec(c, b->left, &rvtype);
+ right = interp_exec(c, b->right, &rtype);
mpq_div(rv.num, rv.num, right.num);
break;
case Rem: {
mpz_t l, r, rem;
- left = interp_exec(b->left, <ype);
- right = interp_exec(b->right, &rtype);
+ left = interp_exec(c, b->left, <ype);
+ right = interp_exec(c, b->right, &rtype);
mpz_init(l); mpz_init(r); mpz_init(rem);
mpz_tdiv_q(l, mpq_numref(left.num), mpq_denref(left.num));
mpz_tdiv_q(r, mpq_numref(right.num), mpq_denref(right.num));
break;
}
case Negate:
- rv = interp_exec(b->right, &rvtype);
+ rv = interp_exec(c, b->right, &rvtype);
mpq_neg(rv.num, rv.num);
break;
case Absolute:
- rv = interp_exec(b->right, &rvtype);
+ rv = interp_exec(c, b->right, &rvtype);
mpq_abs(rv.num, rv.num);
break;
case Bracket:
- rv = interp_exec(b->right, &rvtype);
+ rv = interp_exec(c, b->right, &rvtype);
break;
case Concat:
- left = interp_exec(b->left, <ype);
- right = interp_exec(b->right, &rtype);
+ left = interp_exec(c, b->left, <ype);
+ right = interp_exec(c, b->right, &rtype);
rvtype = Tstr;
rv.str = text_join(left.str, right.str);
break;
+ case StringConv:
+ right = interp_exec(c, b->right, &rvtype);
+ rtype = Tstr;
+ rvtype = Tnum;
+
+ struct text tx = right.str;
+ char tail[3];
+ int neg = 0;
+ if (tx.txt[0] == '-') {
+ neg = 1;
+ tx.txt++;
+ tx.len--;
+ }
+ if (number_parse(rv.num, tail, tx) == 0)
+ mpq_init(rv.num);
+ else if (neg)
+ mpq_neg(rv.num, rv.num);
+ if (tail[0])
+ printf("Unsupported suffix: %.*s\n", tx.len, tx.txt);
+
+ break;
###### value functions
###### Binode types
Block,
-###### expr precedence
- $TERM pass
-
###### Grammar
+ $TERM { } ;
+
$*binode
Block -> { IN OptNL Statementlist OUT OptNL } ${ $0 = $<Sl; }$
| { SimpleStatements } ${ $0 = reorder_bilist($<SS); }$
$0->right = $<1;
}$
+ $TERM pass
SimpleStatement -> pass ${ $0 = NULL; }$
| ERROR ${ tok_err(c, "Syntax error in statement", &$1); }$
## SimpleStatement Grammar
while (rvtype == Tnone &&
b) {
if (b->left)
- rv = interp_exec(b->left, &rvtype);
+ rv = interp_exec(c, b->left, &rvtype);
b = cast(binode, b->right);
}
break;
if (b->left) {
if (sep)
putchar(sep);
- left = interp_exec(b->left, <ype);
+ left = interp_exec(c, b->left, <ype);
print_value(ltype, &left);
free_value(ltype, &left);
if (b->right)
Assign,
Declare,
+###### declare terminals
+ $TERM =
+
###### SimpleStatement Grammar
| Variable = Expression ${
$0 = new(binode);
###### interp binode cases
case Assign:
- lleft = linterp_exec(b->left, <ype);
- right = interp_exec(b->right, &rtype);
+ lleft = linterp_exec(c, b->left, <ype);
+ right = interp_exec(c, b->right, &rtype);
if (lleft) {
free_value(ltype, lleft);
dup_value(ltype, &right, lleft);
struct variable *v = cast(var, b->left)->var;
if (v->merged)
v = v->merged;
+ free_value(v->type, v->val);
+ free(v->val);
if (b->right) {
- right = interp_exec(b->right, &rtype);
- free_value(v->type, v->val);
- free(v->val);
- v->val = val_alloc(v->type, &right);
+ right = interp_exec(c, b->right, &rtype);
+ v->val = val_alloc(c, v->type, &right);
rtype = Tnone;
} else {
- free_value(v->type, v->val);
- v->val = val_alloc(v->type, NULL);
+ v->val = val_alloc(c, v->type, NULL);
}
break;
}
if (v->var->type == Tnone) {
/* Convert this to a label */
v->var->type = Tlabel;
- v->var->val = val_alloc(Tlabel, NULL);
+ v->var->val = val_alloc(c, Tlabel, NULL);
v->var->val->label = v->var->val;
}
}
###### interp binode cases
case Use:
- rv = interp_exec(b->right, &rvtype);
+ rv = interp_exec(c, b->right, &rvtype);
break;
### The Conditional Statement
struct value v, cnd;
struct type *vtype, *cndtype;
struct casepart *cp;
- struct cond_statement *c = cast(cond_statement, e);
+ struct cond_statement *cs = cast(cond_statement, e);
- if (c->forpart)
- interp_exec(c->forpart, NULL);
+ if (cs->forpart)
+ interp_exec(c, cs->forpart, NULL);
do {
- if (c->condpart)
- cnd = interp_exec(c->condpart, &cndtype);
+ if (cs->condpart)
+ cnd = interp_exec(c, cs->condpart, &cndtype);
else
cndtype = Tnone;
if (!(cndtype == Tnone ||
(cndtype == Tbool && cnd.bool != 0)))
break;
// cnd is Tnone or Tbool, doesn't need to be freed
- if (c->dopart)
- interp_exec(c->dopart, NULL);
+ if (cs->dopart)
+ interp_exec(c, cs->dopart, NULL);
- if (c->thenpart) {
- rv = interp_exec(c->thenpart, &rvtype);
- if (rvtype != Tnone || !c->dopart)
+ if (cs->thenpart) {
+ rv = interp_exec(c, cs->thenpart, &rvtype);
+ if (rvtype != Tnone || !cs->dopart)
goto Xcond_done;
free_value(rvtype, &rv);
rvtype = Tnone;
}
- } while (c->dopart);
+ } while (cs->dopart);
- for (cp = c->casepart; cp; cp = cp->next) {
- v = interp_exec(cp->value, &vtype);
+ for (cp = cs->casepart; cp; cp = cp->next) {
+ v = interp_exec(c, cp->value, &vtype);
if (value_cmp(cndtype, vtype, &v, &cnd) == 0) {
free_value(vtype, &v);
free_value(cndtype, &cnd);
- rv = interp_exec(cp->action, &rvtype);
+ rv = interp_exec(c, cp->action, &rvtype);
goto Xcond_done;
}
free_value(vtype, &v);
}
free_value(cndtype, &cnd);
- if (c->elsepart)
- rv = interp_exec(c->elsepart, &rvtype);
+ if (cs->elsepart)
+ rv = interp_exec(c, cs->elsepart, &rvtype);
else
rvtype = Tnone;
Xcond_done:
$void
Ocean -> OptNL DeclarationList
+ ## declare terminals
+
OptNL ->
| OptNL NEWLINE
Newlines -> NEWLINE
###### top level grammar
+ $TERM const
+
DeclareConstant -> const { IN OptNL ConstList OUT OptNL } Newlines
| const { SimpleConstList } Newlines
| const IN OptNL ConstList OUT Newlines
if (!ok)
c->parse_error = 1;
else if (v) {
- struct value res = interp_exec($5, &v->type);
- v->val = val_alloc(v->type, &res);
+ struct value res = interp_exec(c, $5, &v->type);
+ v->val = val_alloc(c, v->type, &res);
}
} }$
c->prog = $<1;
} }$
+ $TERM program
+
$*binode
Program -> program OpenScope Varlist ColonBlock Newlines ${
$0 = new(binode);
return !!ok;
}
- static void interp_prog(struct exec *prog, char **argv)
+ static void interp_prog(struct parse_context *c, struct exec *prog, char **argv)
{
struct binode *p = cast(binode, prog);
struct binode *al;
while (al) {
struct var *v = cast(var, al->left);
struct value *vl = v->var->val;
+ struct value arg;
if (argv[0] == NULL) {
printf("Not enough args\n");
exit(1);
}
- al = cast(binode, al->right);
- if (vl)
- free_value(v->var->type, vl);
+ if (v->var->type != Tstr) {
+ printf("Arg not string!!\n"); // NOTEST
+ exit(2); // NOTEST
+ }
if (!vl) {
- vl = val_alloc(v->var->type, NULL);
+ vl = val_alloc(c, v->var->type, NULL);
v->var->val = vl;
}
- free_value(v->var->type, vl);
- if (!parse_value(v->var->type, argv[0], vl))
- exit(1);
+
+ arg.str.txt = argv[0];
+ arg.str.len = strlen(argv[0]);
+ free_value(Tstr, vl);
+ dup_value(Tstr, &arg, vl);
+
+ al = cast(binode, al->right);
argv++;
}
- v = interp_exec(p->right, &vtype);
+ v = interp_exec(c, p->right, &vtype);
free_value(vtype, &v);
}
name:string
alive:Boolean
- program A B:
+ program Astr Bstr:
print "Hello World, what lovely oceans you have!"
print "Are there", five, "?"
print pi, pie, "but", cake
+ A := $Astr; B := $Bstr
+
/* When a variable is defined in both branches of an 'if',
* and used afterwards, the variables are merged.
*/