NeilBrown [Sat, 18 May 2019 20:46:13 +0000 (06:46 +1000)]
Oceani - Jamison Creek Version
Clean up text and provide new version name.
Additions for this version include:
- type identifiers
- arrays and structs
- global const
- "and then" "or else" "if .. else"
- test suite
- valgrind testing, coverage testing
NeilBrown [Sat, 18 May 2019 13:51:24 +0000 (23:51 +1000)]
oceani: fix merging of conditionally-scoped variables.
The problem here was that the list seen in ->in_scope
includes more than just what is currently in-scope.
It also contains things that have been replaced by new instances
of the name.
These can be detected a they aren't the first variable listed
under their name any more.
NeilBrown [Sat, 18 May 2019 00:11:43 +0000 (10:11 +1000)]
oceani-tests: test code that has been printed
Test that the printed code actually works, as well as being re-printable.
Also simplify the messages so they don't use as much space
and fix a typo "exit1" -> "exit 1"
NeilBrown [Fri, 17 May 2019 13:31:48 +0000 (23:31 +1000)]
scanner: handle missing newline at EOF
If there is no newline at EOF, we can see EOF immediately after
a valid symbol. This can lead to calling close_token() when
state->node is NULL, which crashes.
The code in close_token() only makes sense if state->node is still the
same as token->node. If it isn't, the token must be at the very end of
its code-node, so a different calculation is needed.
NeilBrown [Sat, 11 May 2019 01:41:59 +0000 (11:41 +1000)]
oceani: mark code that doesn't need testing.
Some code is included to check and report impossible
conditions. Failure to exercise this code shouldn't
be seen as a failure of test coverage.
So mark such code as //NOTEST and exclude it
from statistics.
NeilBrown [Fri, 10 May 2019 10:25:01 +0000 (20:25 +1000)]
oceani: fix valgrind-reported errors.
The test suite wasn't running valgrind in a useful way, and wasn't
actually reporting errors.
So fix it to report leaks and unfreed memory, and then fix the
bugs that it finds.
If a NEWLINE is being treated as a grammar symbol which will sometimes
force a reduction, then an apparent SHIFT/REDUCE conflict that could be
resolved to REDUCE by a newline and would default to shift, is expected
and not really a conflict. So don't report those.
NeilBrown [Thu, 9 May 2019 11:13:16 +0000 (21:13 +1000)]
oceani: add conditional expression
[value] if [condition] else [alternate value]
is a conditional expression which will only evaluate and return one of
the two values, depending on the condition.
This has lowest precedence of all expressions.
NeilBrown [Sun, 5 May 2019 01:51:08 +0000 (11:51 +1000)]
mdcode: don't include blank lines at end of section.
completely blank lines (no indent) at the end of a section
should not be considered part of that section, but rather
separation between this and the next section.
So don't include them in the code.
When a section is used, for example, as sample output to
test against actual output in a test suit, having the
stray blank at the end can be problematic.
NeilBrown [Sun, 5 May 2019 01:38:22 +0000 (11:38 +1000)]
mdcode: allow a specific section to be extracted.
Previously, the md2c tool only extracted "File:" sections.
Sometimes we need more control, so allow a second argument
to identify a single section to be extracted. This will
be written to stdout.
NeilBrown [Wed, 1 May 2019 08:22:38 +0000 (18:22 +1000)]
oceani: prepare for adding new types with new syntax.
1/ 'Variable' now returns an 'exec', so other things returning
and 'exec' can be the LHS of an assignment.
2/ provide forward-decls of generic functions so that
new type functions can use them to work with
components of the types.
New linterp_exec() returns an lvalue, (pointer to value)
and individual cases can provide either an lvalue or an rvalue.
This means the RHS of assignment might not be a simple variable,
so we leave the "v = v->merged" part to the "interp exec" for Xvar.
Also, linterp_exec() might return NULL, so be careful.
This might happen, e.g., when an array index is out of bounds.
During parsing and analysis we don't want to "init" a
variable as that can allocate memory - when we add arrays,
we might not know yet how much memory.
So introduce 'prepare' to prepare a value - such that calling
free on it will work - without allocating.
'init' is then called when a variable is declared - unless something
is assigned to it instead.
It was always intended that a type could come between
the : and = of a declaration.
It makes more sense, and simplifies the grammar, if
we stop treating := as ever being a token.
So now : and = are separate tokens.
If the parse sees ":=", it will happily treat that
as two separate tokens, which is what we want.
Rather than a enum listing allowed types, we now
have a 'struct type' which can contain any type.
For now it just has an enum and function pointer
to the existing function, but that can be extended.
It is never used so there isn't much point
storing it. If/When we do use it, we'll
parse it immediately and store the meaning.
And in any case, it should be char[3].
NeilBrown [Mon, 19 Feb 2018 05:58:40 +0000 (16:58 +1100)]
oceani: minimal error tracking.
1/ If the parser hits an error, catch it at eof by having
Program -> ERROR
2/ Allow the presence of and error to be recorded in the context.
3/ If an error occured, don't try to run, and do exit with an error
status.
NeilBrown [Mon, 19 Feb 2018 05:46:04 +0000 (16:46 +1100)]
oceani: Expression etc should be 'exec', not 'binode'.
As a 'var' and a 'val' are possible expressions,
'binode' isn't correct. This is obvious when you
consider that I needed to case $1 for a var or var
before assigning it to $0 for Factor -> Value etc.
So change all these to expect the more generic 'struct exec *'.
Without this change, error handling can try to free a var as though it
was a binode, and get into trouble.
NeilBrown [Mon, 19 Feb 2018 05:40:06 +0000 (16:40 +1100)]
parsergen: enable error handling.
The error handling code currently aborts early because
it was badly broken.
After recent changes it works well enough for experimenting,
so remove the exit(1) and other unnecessary code, and
let's experiment.
NeilBrown [Mon, 19 Feb 2018 05:38:12 +0000 (16:38 +1100)]
parsergen: improve symbol-discard in error handling.
As we don't keep the full look-ahead set, we need to pay a
bit more attention when discarding input symbols, looking
for one we recognize. We need to consider anything
that can be shifted in any state we can reach by simple
shifting.
NeilBrown [Mon, 19 Feb 2018 05:31:14 +0000 (16:31 +1100)]
parsergen: be careful shifting TK_error
shift() behaved a little differently when p.tos == 0,
and if the stack is completely empty, there is little
point trying to shift TK_error as there is no state
to work with.
NeilBrown [Mon, 19 Feb 2018 04:32:46 +0000 (15:32 +1100)]
parsergen: remove symbol synthesis option.
This idea never worked, and cannot work as we cannot
magically synthesis the ast node to go with a synthesized
symbol.
If we want to synthesize something on error, we just use
a production like
foo -> ERRROR ${ $0 = a_new_for(); }$
NeilBrown [Sun, 18 Feb 2018 05:10:59 +0000 (16:10 +1100)]
scanner: fix calculation of column.
When we stripe the expected indent from the
start of each line, we need to update 'col'
to correctly account for tabs.
Previous code effectively assumed tabs were 4 spaces.
NeilBrown [Wed, 31 Jan 2018 03:25:16 +0000 (14:25 +1100)]
New lang: Stoney Creek
This is the second iteration of language design.
it adds scopes variables.
Variables must be declared before use, but they
can be declared in both branches of an 'if', then
used afterwards as the one variable.
No hole-in-scope is allowed: names that are declared
cannot be redeclared in a subordinate scope.
A test program is included:
make sayhello
Note that there are no useful error messages yet.
That is the next step.
NeilBrown [Mon, 29 Jan 2018 05:20:01 +0000 (16:20 +1100)]
parsergen.mdc: add precedence handling
This hasn't been documented properly in the text yet, but
the example has been changed to work and it seems good.
There is no support for precedence to select between two
reductions because I don't believe that ever happens :-) and
I haven't done anything special for non-associative because
I don't know what I would do.
NeilBrown [Tue, 6 Feb 2018 05:42:01 +0000 (16:42 +1100)]
parsergen: record line number of reduce fragments.
If there is an error in a code fragment used to handle
a 'reduce' action, we need the compiler to report the
correct line from the grammar file.
This information is easily available from the scanner,
we just need to pass it along.
NeilBrown [Fri, 3 Oct 2014 04:30:36 +0000 (14:30 +1000)]
parsergen: remove special casing for pop(0).
If pop() is asked to remove nothing from the stack, it now
does exactly the right thing and returns the value that we want.
So some special-casing can be removed.
NeilBrown [Fri, 3 Oct 2014 03:28:32 +0000 (13:28 +1000)]
parsergen: revise rule for NEWLINE forcing reduce
If the whole line is a single symbol, then it isn't appropriate
for a NEWLINE to force a reduce (it may be for an OUT, but as the
NEWLINE shifts (the OUT doesn't) we don't need to push so hard).
NeilBrown [Fri, 3 Oct 2014 03:24:36 +0000 (13:24 +1000)]
parsergen: don't use 'frame' to pass args to shift() or receive from pop()
'struct frame' holds a number of fields that shift()
ignores and pop() doesn't fill in.
So it is a bit confusing to see a frame passed in
and mostly ignored.
So just pass in the fields that are actually needed.
This fixes a bug where 'since_newline' was set wrongly when a newline
is shifted.