more/better examples
This commit is contained in:
parent
9ec2dffd1b
commit
fb236bd835
18
examples/builtins.txt
Normal file
18
examples/builtins.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
We can just put all "builtins" into a file, then ship together with SLC and let it use them.
|
||||||
|
|
||||||
|
I think this is cleaner than adding syntax that makes the parser and interpreter just unnecessarily more complex...
|
||||||
|
|
||||||
|
So there does not need to be the following 4 variations:
|
||||||
|
|
||||||
|
: regularword
|
||||||
|
:: compileword
|
||||||
|
:builtin regularword
|
||||||
|
::builtin compileword
|
||||||
|
|
||||||
|
^^ if I somehoe let the interpreter know what the builtins are and define them all together in a differen parser state...
|
||||||
|
|
||||||
|
So the parser would in that mode prefix everything with the prefix - and in the symbol table of course enter the real C builtins
|
||||||
|
with the prefix too. Also in the calls / code of these, we would prefix everything to look up well in the symbol table so the code
|
||||||
|
for builtins can be totally unprefixed and all.
|
||||||
|
|
||||||
|
This really helps to simplify the parser-statemachine in my opinion - also the interpreter state machine should be unaffected!
|
@ -1,26 +1,28 @@
|
|||||||
/*
|
// A parseblock_outer should change return address,
|
||||||
Parses this:
|
// so parsing continues at a different location!
|
||||||
|
// This is needed because we have processed the
|
||||||
|
// stuff AFTER the word "do"...
|
||||||
|
|
||||||
do {
|
::builtin do
|
||||||
...code...
|
parseword
|
||||||
} (...cond...)
|
if("(" streq) {
|
||||||
|
drop parseword
|
||||||
Into this:
|
if(")" streq) {
|
||||||
|
"" parseblock_outer()
|
||||||
...code...
|
}
|
||||||
while(...cond...) {
|
} [
|
||||||
...code...
|
if("[" streq) {
|
||||||
}
|
drop parseword
|
||||||
*/
|
if("]" streq) {
|
||||||
|
"" parseblock_outer[]
|
||||||
// -> [bytecodes]
|
}
|
||||||
::builtin do @body
|
} [
|
||||||
"" parseblock {} // "" means no entry into the symbol table (unnamed function) - equals to 0
|
if("{" streq) {
|
||||||
do@body(.) // (.) does not removes - only (_) no need for gencode because
|
drop parseword
|
||||||
gen(while) // address top bit 1 when builtin from C
|
if("}" streq) {
|
||||||
genopen() // equal to gencode(1)
|
"" parseblock_outer{}
|
||||||
"" parseblock ()
|
}
|
||||||
genclose()
|
}
|
||||||
genopen{}
|
]
|
||||||
do@body
|
]
|
||||||
genclose{}
|
;
|
||||||
|
27
examples/dowhile.slc
Normal file
27
examples/dowhile.slc
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
Parses this:
|
||||||
|
|
||||||
|
dowhile {
|
||||||
|
...code...
|
||||||
|
} (...cond...)
|
||||||
|
|
||||||
|
Into this:
|
||||||
|
|
||||||
|
...code...
|
||||||
|
while(...cond...) {
|
||||||
|
...code...
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// -> [bytecodes]
|
||||||
|
::builtin dowhile @body
|
||||||
|
"" parseblock {} // "" means no entry into the symbol table (unnamed function) - equals to 0
|
||||||
|
do@body(.) // (.) does not removes - only (_) no need for gencode because
|
||||||
|
gen(while) // address top bit 1 when builtin from C
|
||||||
|
genopen() // equal to 1 gencode(_)
|
||||||
|
"" parseblock ()
|
||||||
|
genclose()
|
||||||
|
genopen{}
|
||||||
|
do@body
|
||||||
|
genclose{}
|
||||||
|
;
|
@ -1,12 +1,62 @@
|
|||||||
// prefixed builtins with '#'
|
// Implementing if statement if its not a built-in in SLC!
|
||||||
// when writing a compiler - like a c-like language
|
// Not compiler writing in SLC language, but SLCs builtin itself...
|
||||||
|
|
||||||
:if
|
::builtin if @cmp @then @else
|
||||||
()
|
"" parseblock() // (*)
|
||||||
#asm(jz else$)
|
if@cmp(.)
|
||||||
{}
|
"" parseblock{}
|
||||||
#asm(jmp ifend$)
|
if@then(_)
|
||||||
#asm(else$:)
|
// returns 0 if there was no [] block!
|
||||||
[]
|
// Calling 0 means just calling the
|
||||||
#asm(ifend$:)
|
// intstruction pointer ("avoiding call")
|
||||||
|
"" parseblock[]
|
||||||
|
if@else(_)
|
||||||
|
|
||||||
|
// (*) cmp result at top of stack
|
||||||
|
gen(!) gen(skipif) if@then
|
||||||
|
gen(skipif) if@else
|
||||||
|
;
|
||||||
|
|
||||||
|
// Alternatively - by adding "branchcall" to the builtins
|
||||||
|
::builtin if
|
||||||
|
"" parseblock()
|
||||||
|
genpush(_)
|
||||||
|
"" parseblock{}
|
||||||
|
genpush(_)
|
||||||
|
"" parseblock[] // returns 0 if there was no block (its SKIP to 'call' 0)
|
||||||
|
genpush(_)
|
||||||
|
gen(branchcall)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Rem.: "branchcall" can be used in "real" code to split which word to call...
|
||||||
|
|
||||||
|
: smaller
|
||||||
|
"smaller"
|
||||||
|
;
|
||||||
|
|
||||||
|
: bigger
|
||||||
|
"bigger-or-eq"
|
||||||
|
;
|
||||||
|
|
||||||
|
// Gets a b
|
||||||
|
// returns "smaller" or "bigger-or-eq"
|
||||||
|
: smaller_or_bigger
|
||||||
|
<
|
||||||
|
gen(smaller)
|
||||||
|
gen(bigger)
|
||||||
|
branchcall
|
||||||
|
;
|
||||||
|
|
||||||
|
// Better example
|
||||||
|
|
||||||
|
: one 1 ;
|
||||||
|
: zero 0 ;
|
||||||
|
|
||||||
|
// Gets a b
|
||||||
|
// returns 1 if a < b, 0 otherwise
|
||||||
|
: smaller_or_bigger
|
||||||
|
<
|
||||||
|
gen(one)
|
||||||
|
gen(zero)
|
||||||
|
branchcall
|
||||||
;
|
;
|
||||||
|
11
examples/if_compiler.slc
Normal file
11
examples/if_compiler.slc
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// when writing a compiler - like a c-like language
|
||||||
|
|
||||||
|
:if
|
||||||
|
#do()
|
||||||
|
#asm(jz else$)
|
||||||
|
#do{}
|
||||||
|
#asm(jmp ifend$)
|
||||||
|
#asm(else$:)
|
||||||
|
#do[]
|
||||||
|
#asm(ifend$:)
|
||||||
|
;
|
20
examples/loop.slc
Normal file
20
examples/loop.slc
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Easiest way to create loops are "misusing" the call stack!
|
||||||
|
// That is instead of creating "real" loops in SLC or labels and GOTOs,
|
||||||
|
// we can have a word (loop) that basically calls to its own code location.
|
||||||
|
|
||||||
|
// A do-while loop is then as follows:
|
||||||
|
|
||||||
|
loop
|
||||||
|
....
|
||||||
|
if(feltétel) { ret } [ endloop ]
|
||||||
|
|
||||||
|
|
||||||
|
// A while-loop is then as follows:
|
||||||
|
|
||||||
|
loop if(feltétel) {
|
||||||
|
...
|
||||||
|
ret
|
||||||
|
} endloop
|
||||||
|
|
||||||
|
// Rem.: "ret" is literally the written-out word for returning; endloop is "removing" (and throwing away) call stack top.
|
||||||
|
// Rem.: This does not make "loops into recursion" because the stack does not grow while loop is going on!
|
Loading…
x
Reference in New Issue
Block a user