myLDLIBS:= libparser.o libscanner.o libmdcode.o -licuuc
LDLIBS := $(filter-out $(myLDLIBS),$(LDLIBS)) $(myLDLIBS)
## libs
- all :: oceani
+ all :: $(LDLIBS) oceani
oceani.c oceani.h : oceani.mdc parsergen
./parsergen -o oceani --LALR --tag Parser oceani.mdc
oceani.mk: oceani.mdc md2c
static int parse_value(struct value *vl, char *arg)
{
struct text tx;
+ int neg = 0;
switch(vl->vtype) {
case Vunknown:
case Vnone:
memcpy(vl->str.txt, arg, vl->str.len);
break;
case Vnum:
+ if (*arg == '-') {
+ neg = 1;
+ arg++;
+ }
tx.txt = arg; tx.len = strlen(tx.txt);
if (number_parse(vl->num, vl->tail, tx) == 0)
mpq_init(vl->num);
+ else if (neg)
+ mpq_neg(vl->num, vl->num);
break;
case Vbool:
if (strcasecmp(arg, "true") == 0 ||
Each different type of `exec` node needs a number of functions
defined, a bit like methods. We must be able to be able to free it,
print it, analyse it and execute it. Once we have specific `exec`
-types we will need to parse them to. Let's take this a bit more
+types we will need to parse them too. Let's take this a bit more
slowly.
#### Freeing
-The parser generator requires as `free_foo` function for each struct
+The parser generator requires a `free_foo` function for each struct
that stores attributes and they will be `exec`s of subtypes there-of.
So we need `free_exec` which can handle all the subtypes, and we need
`free_binode`.
#### Analysing
-As discusses, analysis involves propagating type requirements around
+As discussed, analysis involves propagating type requirements around
the program and looking for errors.
-So propagate_types is passed a type that the `exec` is expected to return,
+So `propagate_types` is passed a type that the `exec` is expected to return,
and returns the type that it does return, either of which can be `Vunknown`.
An `ok` flag is passed by reference. It is set to `0` when an error is
found, and `2` when any change is made. If it remains unchanged at
{
enum vtype t;
- if (!prog) {
- if (type != Vunknown && type != Vnone)
- *ok = 0;
+ if (!prog)
return Vnone;
- }
switch (prog->type) {
case Xbinode:
$0->val.vtype = Vstr;
string_parse(&$1, '\\', &$0->val.str, $0->val.tail);
}$
+ | MULTI_STRING ${
+ $0 = new(val);
+ $0->val.vtype = Vstr;
+ string_parse(&$1, '\\', &$0->val.str, $0->val.tail);
+ }$
###### print exec cases
case Xval:
Boolean expressions. As I haven't implemented precedence in the
parser generator yet, we need different names from each precedence
level used by expressions. The outer most or lowest level precedence
-are Boolean `or` `and`, and `not` which form and `Expression` our of `BTerm`s
+are Boolean `or` `and`, and `not` which form an `Expression` out of `BTerm`s
and `BFact`s.
###### Binode types
$0->left = $<1;
$0->right = $<3;
}$
- | Expr ${ $0 = $<1; }$
+ | Expr ${ $0 = $<1; }$
###### Grammar
Close -> }
| NEWLINE }
Block -> Open Statementlist Close ${ $0 = $<2; }$
+ | Open Newlines Statementlist Close ${ $0 = $<3; }$
| Open SimpleStatements } ${ $0 = reorder_bilist($<2); }$
+ | Open Newlines SimpleStatements } ${ $0 = reorder_bilist($<3); }$
| : Statementlist ${ $0 = $<2; }$
| : SimpleStatements ${ $0 = reorder_bilist($<2); }$
### The Conditional Statement
This is the biggy and currently the only complex statement.
-This subsumes `if`, `while`, `do/while`, `switch`, and some part of
+This subsumes `if`, `while`, `do/while`, `switch`, and some parts of
`for`. It is comprised of a number of parts, all of which are
optional though set combinations apply.
to completion. This is treated the same as returning True.
If there is a `thenpart` it will be executed whenever the `condpart`
-or `cond` returns True (or does not return), but this will happen
+or `cond` returns True (or does not return any value), but this will happen
*after* `dopart` (when present).
If `elsepart` is present it will be executed at most once when the
The particular sorts of values allowed in case parts has not yet been
determined in the language design.
-The cond_statement cannot fit into a `binode` so a new `exec` is
+The `cond_statement` cannot fit into a `binode` so a new `exec` is
defined.
###### exec type
cast(binode, cs->condpart)->op == Block) {
printf(":\n");
print_exec(cs->condpart, indent+1, bracket);
- do_indent(indent, "then:\n");
- print_exec(cs->thenpart, indent+1, bracket);
+ if (cs->thenpart) {
+ do_indent(indent, "then:\n");
+ print_exec(cs->thenpart, indent+1, bracket);
+ }
} else {
printf(" ");
print_exec(cs->condpart, 0, bracket);
- printf(":\n");
- print_exec(cs->thenpart, indent+1, bracket);
+ if (cs->thenpart) {
+ printf(":\n");
+ print_exec(cs->thenpart, indent+1, bracket);
+ } else
+ printf("\n");
}
}
for (cp = cs->casepart; cp; cp = cp->next) {
### Finally the whole program.
Somewhat reminiscent of Pascal a (current) Ocean program starts with
-the keyword "program" and list of variable names which are assigned
+the keyword "program" and a list of variable names which are assigned
values from command line arguments. Following this is a `block` which
is the code to execute.