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 type *type);
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)
{
struct value *ret;
- if (!t->size)
- val_init(t, NULL);
+ if (t->prepare_type)
+ t->prepare_type(t);
+
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 lrval ret = _interp_exec(e);
- if (typeret)
+ if (ret.lval)
*typeret = ret.type;
+ else
+ free_value(ret.type, &ret.rval);
return ret.lval;
}
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
struct type *member;
} array;
-###### value union fields
- void *array;
-
###### value functions
- static void array_init(struct type *type, struct value *val)
+ static void array_prepare_type(struct type *type)
{
- int i;
+ mpz_t q;
+ if (!type->array.vsize)
+ return;
+
+ 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 (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);
- }
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;
if (!val)
return;
static struct type array_prototype = {
.init = array_init,
+ .prepare_type = array_prepare_type,
.print_type = array_print_type,
.compat = array_compat,
.free = array_free,
};
+###### 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->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,
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 ${ {
###### 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);
right = interp_exec(b->right, &rvtype);
rtype = Tstr;
rvtype = Tnum;
- char *str = strndup(right.str.txt, right.str.len);
- parse_value(rvtype, str, &rv);
- free(str);
+
+ 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
Assign,
Declare,
+###### declare terminals
+ $TERM =
+
###### SimpleStatement Grammar
| Variable = Expression ${
$0 = new(binode);
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);
rtype = Tnone;
} else {
- free_value(v->type, v->val);
v->val = val_alloc(v->type, NULL);
}
break;
$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
c->prog = $<1;
} }$
+ $TERM program
+
$*binode
Program -> program OpenScope Varlist ColonBlock Newlines ${
$0 = new(binode);
v->var->val = vl;
}
free_value(v->var->type, vl);
- if (!parse_value(v->var->type, argv[0], vl))
- exit(1);
+ vl->str.len = strlen(argv[0]);
+ vl->str.txt = malloc(vl->str.len);
+ memcpy(vl->str.txt, argv[0], vl->str.len);
argv++;
}
v = interp_exec(p->right, &vtype);