Age | Commit message (Collapse) | Author |
|
|
|
|
|
Lexer now will straight away attempt to eat up any type or later
portions of an opcode rather than leaving everything but the root.
This means checking for type in the parser is a direct check against
the name rather than prefixed with a dot.
Checks are a bit more strong to cause more tokens to go straight to
symbol rather than getting checked after one routine in at on the
parser side.
|
|
This was due to the beg or end page being not set correctly (dangling
pointer).
|
|
Stack, call stack and heap are evaluated to check for leaks.
|
|
Very easy overall, printing the call stack not so much.
|
|
Essentially you may "call" an absolute program address, which pushes
the current address onto the call stack. CALL_STACK does the same
thing but the absolute program address is taken from the data stack.
RET pops an address off the call stack then jumps to that address.
|
|
Makes more sense, don't need to fiddle around with strings as much in
the parser due to this!
|
|
|
|
Not necessary when you can just push the relevant word onto the stack
then just do OP_JUMP_STACK.
|
|
|
|
Essentially a presult_t contains one of these:
1) A label construction, which stores the label symbol into
`label` (PRES_LABEL)
2) An instruction that calls upon a label, storing the instruction
in `instruction` and the label name in `label` (PRES_LABEL_ADDRESS)
3) An instruction that uses a relative address offset, storing the
instruction in `instruction` and the offset wanted into
`relative_address` (PRES_RELATIVE_ADDRESS)
4) An instruction that requires no further processing, storing the
instruction into `instruction` (PRES_COMPLETE_INSTRUCTION)
In the processing stage, we resolve all calls by iterating one by one
and maintaining an absolute instruction address. Pretty nice, lots
more machinery involved in parsing now.
|
|
|
|
|
|
bytes, returning a new set
|
|
|
|
|
|
|
|
MALLOC_STACK is a stack based version of MALLOC, SUB does subtraction.
|
|
Happened because we weren't printing all relevant words due to
naturally flooring the result of division. Here I ceil the division
to ensure we get the maximal number of words necessary.
|
|
|
|
|
|
|
|
Very easy, they just pop a word then defer to their normal versions.
This is probably the best case where a macro works directly so I
didn't even need to write a function form for them first. One thing
is that then names for the macros are quite bad right now, probably
need renaming.
|
|
Essentially they use the stack for their one and only operand. This
allows user level control, in particular it allows for loops to work
correctly while using these operands.
|
|
|
|
|
|
This will allow for more library level code to be written. For
example, say you wanted to write a generic byte level reversal
algorithm for dynamically sized allocations. Getting the size of the
allocation would be fundamental to this operation.
|
|
|
|
Pretty simple implementation, nothing massive.
In VERBOSE mode, heap is tracked for any allocations/deletions,
printing it if so.
|
|
Pretty simple, required some new types of errors. Obviously there's
space for a macro for the differing instruction implementations, but
these things need to be tested a bit more before I can do that.
|
|
One may allocate any number of (bytes|hwords|words), set or get some
index from allocated memory, and delete heap memory.
The idea is that all the relevant datums will be on the stack, so no
register usage. This means no instructions should use register space
at all (other than POP, which I'm debating about currently). Register
space is purely for users.
|
|
As PUSH_REGISTER and MOV have the same signature of taking a word as
input, DUP may as well be part of it.
This leads to a larger discussion about how signatures of functions
matter: I may need to do a cleanup at some point.
|
|
|
|
Instead of having each page be an area of memory, where multiple
pointers to differing data may lie, we instead have each page being
one allocation. This ensures that a deletion algorithm, as provided,
would actually work without destroying older pointers which may have
been allocated. Great!
|
|
Now need to create some instructions which manage the heap
|
|
A page is a flexibly allocated structure of bytes, with a count of the
number of bytes already allocated (used) and number of bytes available
overall (available), with a pointer to the next page, if any.
heap_t is a linked list of pages. One may allocate a requested size
off the heap which causes one of two things:
1) Either a page already exists with enough space for the requested
size, in which case that page's pointer is used as the base for the
requested pointer
2) No pages satisfy the requested size, so a new page is allocated
which is the new end of the heap.
|
|
|
|
|
|
|
|
|
|
word register 0 refers to the first 8 bytes of the dynamic array.
Hence the used counter should be at least 8 bytes. This deals with
those issues. Also print more useful information in
vm_print_registers (how many byte|hword|word registers are currently
in use, how many are available).
|
|
Dependencies are just ASM_OUT binary and the corresponding assembly
program for the bytecode output file. Actually works very well, with
changes triggering a recompilation. Also an `exec` recipe is
introduced to do the task of compiling an assembly program and
executing the corresponding bytecode all at once.
|
|
|
|
Very cool, easy, and reads well
|
|
|
|
Lucky surprise: OP_PLUS follows the same principle rules as the
bitwise operators in that they return the same type as the input.
Therefore I can simply use the same macro to implement it and MULT as
those. Very nice.
|
|
|
|
Thankfully multiplication, like addition, is the same under 2s
complement as it is for unsigned numbers. So I just need to implement
those versions to be fine.
|
|
By default I initialise the registers with 8 words, though this may
not be necessary for your purposes.
|