sub decl checking

This commit is contained in:
Irmen de Jong 2018-09-19 02:41:35 +02:00
parent cba9e7670e
commit b72bd805e1
8 changed files with 92 additions and 44 deletions

View File

@ -63,11 +63,11 @@ statement :
| branch_stmt
| subroutine
| inlineasm
| labeldef
| returnstmt
| forloop
| breakstmt
| continuestmt
| labeldef
// @todo whileloop, repeatloop
;

View File

@ -17,12 +17,13 @@
word plotx
byte ploty
_vm_write_str("Calculating Mandelbrot fractal, have patience...\n")
_vm_gfx_clearscr(11)
for pixely in 0 to height { ; @todo 255 as upper limit doesn't work it overflows the loop
for pixelx in 0 to width {
xx=flt(pixelx)/width/3+0.2 ; @todo fix division to return float always, add // integer division
yy=flt(pixely)/height/3.6+0.4
xx=pixelx/width/3+0.2
yy=pixely/height/3.6+0.4
x=0.0
y=0.0

View File

@ -6,33 +6,51 @@
sub start() -> () {
const word width = 159
const word height = 127
word pixelx
byte pixely
float xx
float yy
float x = 4999.999
float y
float x2
byte iter
word plotx = 40000
byte ploty
if(X) goto yesx
else goto nox
;yy = pixelx/width/3+0.2 ; @todo fix division to return float always, add // integer division
;xx = flt(pixelx)/width/3+0.2 ; @todo fix division to return float always, add // integer division
_vm_write_num(plotx)
_vm_write_char($8d)
plotx //= 3 ; @todo fix division to return float always, add // integer division
_vm_write_num(plotx)
_vm_write_char($8d)
yesx:
x2 = x/33.33 ; @todo fix division to return float always, add // integer division
_vm_write_num(x2)
_vm_write_char($8d)
x2 = x//33.33 ; @todo fix division to return float always, add // integer division
_vm_write_num(x2)
_vm_write_char($8d)
if(X) {
A=0
goto yesx ;; @todo fix undefined symbol error
return
} else {
A=1
goto nox
}
return
sub bla() -> () {
return
sub fooz() -> () {
return
}
sub fooz2() -> () {
return
}
return
}
A=45
nox:
word i
for i in 10 to 20 {
if(i>12) goto fout ;; @todo fix undefined symbol error
break
continue
bla() ;; @todo fix undefined symbol error
}
fout:
return
}
}

View File

@ -15,7 +15,10 @@ import kotlin.system.exitProcess
fun main(args: Array<String>) {
println("\nProg8 compiler by Irmen de Jong (irmen@razorvine.net)")
println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n")
// @todo software license string
// println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n")
println("**** This is a prerelease version. Please do not distribute! ****\n")
if(args.size != 1) {
System.err.println("requires one argument: name of module file")
exitProcess(1)

View File

@ -139,10 +139,19 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
checkResult.add(SyntaxError("block memory address must be valid integer 0..\$ffff", block.position))
}
checkSubroutinesPrecededByReturnOrJump(block.statements)
checkSubroutinesPrecededByReturnOrJumpAndFollowedByLabelOrSub(block.statements)
return super.process(block)
}
override fun process(label: Label): IStatement {
// scope check
if(label.parent !is Block && label.parent !is Subroutine) {
checkResult.add(SyntaxError("Labels can only be defined in the scope of a block or within another subroutine", label.position))
}
return super.process(label)
}
/**
* Check subroutine definition
*/
@ -166,7 +175,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
err("return registers should be unique")
super.process(subroutine)
checkSubroutinesPrecededByReturnOrJump(subroutine.statements)
checkSubroutinesPrecededByReturnOrJumpAndFollowedByLabelOrSub(subroutine.statements)
// subroutine must contain at least one 'return' or 'goto'
// (or if it has an asm block, that must contain a 'rts' or 'jmp')
@ -184,12 +193,24 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
}
}
// scope check
if(subroutine.parent !is Block && subroutine.parent !is Subroutine) {
err("subroutines can only be defined in the scope of a block or within another subroutine")
}
return subroutine
}
private fun checkSubroutinesPrecededByReturnOrJump(statements: MutableList<IStatement>) {
private fun checkSubroutinesPrecededByReturnOrJumpAndFollowedByLabelOrSub(statements: MutableList<IStatement>) {
// @todo hmm, or move all the subroutines at the end of the block? (no fall-through execution)
var preceding: IStatement = BuiltinFunctionStatementPlaceholder
var checkNext = false
for (stmt in statements) {
if(checkNext) {
if(stmt !is Label && stmt !is Subroutine)
checkResult.add(SyntaxError("preceding subroutine definition at line ${preceding.position.line} should be followed here by a label, another subroutine statement, or nothing", stmt.position))
return
}
if(stmt is Subroutine) {
if(preceding !is Return
&& preceding !is Jump
@ -198,6 +219,7 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions:
&& preceding !is BuiltinFunctionStatementPlaceholder) {
checkResult.add(SyntaxError("subroutine definition should be preceded by a return, jump, vardecl, or another subroutine statement", stmt.position))
}
checkNext=true
}
preceding = stmt
}

View File

@ -116,6 +116,7 @@ class Compiler(private val options: CompilationOptions) {
class VarGatherer(private val stackvmProg: StackVmProgram): IAstProcessor {
// collect all the VarDecls to make them into one global list
// @todo maybe keep the block structure intact and allocate them per block? this is needed eventually for the actual 6502 code generation so...
override fun process(decl: VarDecl): IStatement {
if(decl.type == VarDeclType.MEMORY)
TODO("stackVm doesn't support memory vars for now")

View File

@ -367,9 +367,6 @@ public class prog8Parser extends Parser {
public InlineasmContext inlineasm() {
return getRuleContext(InlineasmContext.class,0);
}
public LabeldefContext labeldef() {
return getRuleContext(LabeldefContext.class,0);
}
public ReturnstmtContext returnstmt() {
return getRuleContext(ReturnstmtContext.class,0);
}
@ -382,6 +379,9 @@ public class prog8Parser extends Parser {
public ContinuestmtContext continuestmt() {
return getRuleContext(ContinuestmtContext.class,0);
}
public LabeldefContext labeldef() {
return getRuleContext(LabeldefContext.class,0);
}
public StatementContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@ -497,35 +497,35 @@ public class prog8Parser extends Parser {
enterOuterAlt(_localctx, 15);
{
setState(133);
labeldef();
returnstmt();
}
break;
case 16:
enterOuterAlt(_localctx, 16);
{
setState(134);
returnstmt();
forloop();
}
break;
case 17:
enterOuterAlt(_localctx, 17);
{
setState(135);
forloop();
breakstmt();
}
break;
case 18:
enterOuterAlt(_localctx, 18);
{
setState(136);
breakstmt();
continuestmt();
}
break;
case 19:
enterOuterAlt(_localctx, 19);
{
setState(137);
continuestmt();
labeldef();
}
break;
}
@ -3496,9 +3496,9 @@ public class prog8Parser extends Parser {
"\2\2y\u008d\5\16\b\2z\u008d\5\24\13\2{\u008d\5\22\n\2|\u008d\5\26\f\2"+
"}\u008d\5\30\r\2~\u008d\5\36\20\2\177\u008d\5 \21\2\u0080\u008d\5\f\7"+
"\2\u0081\u008d\5$\23\2\u0082\u008d\5*\26\2\u0083\u008d\5Z.\2\u0084\u008d"+
"\5^\60\2\u0085\u008d\5L\'\2\u0086\u008d\5J&\2\u0087\u008d\5\n\6\2\u0088"+
"\u008d\5.\30\2\u0089\u008d\5b\62\2\u008a\u008d\5\60\31\2\u008b\u008d\5"+
"\62\32\2\u008cy\3\2\2\2\u008cz\3\2\2\2\u008c{\3\2\2\2\u008c|\3\2\2\2\u008c"+
"\5^\60\2\u0085\u008d\5L\'\2\u0086\u008d\5J&\2\u0087\u008d\5.\30\2\u0088"+
"\u008d\5b\62\2\u0089\u008d\5\60\31\2\u008a\u008d\5\62\32\2\u008b\u008d"+
"\5\n\6\2\u008cy\3\2\2\2\u008cz\3\2\2\2\u008c{\3\2\2\2\u008c|\3\2\2\2\u008c"+
"}\3\2\2\2\u008c~\3\2\2\2\u008c\177\3\2\2\2\u008c\u0080\3\2\2\2\u008c\u0081"+
"\3\2\2\2\u008c\u0082\3\2\2\2\u008c\u0083\3\2\2\2\u008c\u0084\3\2\2\2\u008c"+
"\u0085\3\2\2\2\u008c\u0086\3\2\2\2\u008c\u0087\3\2\2\2\u008c\u0088\3\2"+

View File

@ -1464,7 +1464,10 @@ class StackVm(val traceOutputFile: String?) {
fun main(args: Array<String>) {
println("\nProg8 StackVM by Irmen de Jong (irmen@razorvine.net)")
println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n")
// @todo software license string
// println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n")
println("**** This is a prerelease version. Please do not distribute! ****\n")
if(args.size != 1) {
System.err.println("requires one argument: name of stackvm sourcecode file")
exitProcess(1)