fix the check of double-defined subroutine variables

This commit is contained in:
Irmen de Jong 2021-11-28 12:50:35 +01:00
parent c52aa648c0
commit 0a568f2530
3 changed files with 31 additions and 30 deletions

View File

@ -18,11 +18,22 @@ import prog8.compilerinterface.*
internal class BeforeAsmGenerationAstChanger(val program: Program, private val options: CompilationOptions,
private val errors: IErrorReporter) : AstWalker() {
private val subroutineVariables = mutableMapOf<Subroutine, MutableList<Pair<String, VarDecl>>>()
private fun rememberSubroutineVar(decl: VarDecl) {
val sub = decl.definingSubroutine ?: return
var varsList = subroutineVariables[sub]
if(varsList==null) {
varsList = mutableListOf()
subroutineVariables[sub] = varsList
}
varsList.add(decl.name to decl)
}
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
if(decl.type==VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes)
throw FatalAstException("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl")
subroutineVariables.add(decl.name to decl)
rememberSubroutineVar(decl)
return noModifications
}
@ -68,26 +79,16 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
return noModifications
}
private val subroutineVariables = mutableListOf<Pair<String, VarDecl>>()
override fun before(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
subroutineVariables.clear()
return noModifications
}
override fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> {
if(scope.statements.any { it is VarDecl || it is IStatementContainer })
throw FatalAstException("anonymousscope may no longer contain any vardecls or subscopes")
val decls = scope.statements.filterIsInstance<VarDecl>().filter { it.type == VarDeclType.VAR }
subroutineVariables.addAll(decls.map { it.name to it })
return noModifications
}
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
val firstDeclarations = mutableMapOf<String, VarDecl>()
for(decl in subroutineVariables) {
val rememberedSubroutineVars = subroutineVariables.getOrDefault(subroutine, mutableListOf())
for(decl in rememberedSubroutineVars) {
val existing = firstDeclarations[decl.first]
if(existing!=null && existing !== decl.second) {
errors.err("variable ${decl.first} already defined in subroutine ${subroutine.name} at ${existing.position}", decl.second.position)
@ -95,7 +96,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
firstDeclarations[decl.first] = decl.second
}
}
rememberedSubroutineVars.clear()
// add the implicit return statement at the end (if it's not there yet), but only if it's not a kernal routine.
// and if an assembly block doesn't contain a rts/rti, and some other situations.

View File

@ -8,7 +8,7 @@ Use GoSub to call subroutines (statements):
- [DONE] turn a regular subroutine call into assignments to the parameters + GoSub (take code from gosub branch)
- [DONE] also do this for asmsubs taking >0 parameters
- make that push(x+1) doesn't use stack evaluation, via a temp var?
- make that push(x+1) doesn't use stack evaluation, via a temp var cx16.R9?
Optimize Function calls in expressions:
- move args to assignments to params

View File

@ -15,21 +15,21 @@ main {
ubyte @shared ub
word @shared ww
; push(127)
; pop(ub)
; txt.print_ub(ub)
; txt.nl()
; pushw(32767)
; popw(uw)
; txt.print_uw(uw)
; txt.nl()
push(127)
pop(ub)
txt.print_ub(ub)
txt.nl()
pushw(32767)
popw(uw)
txt.print_uw(uw)
txt.nl()
uw=10000
routines(44,uw+123)
routines2(44,uw+123)
routine(uw+123, 22,33, true, 44)
routine2(uw+123, 22,33, true, 44)
; uw=10000
; routines(44,uw+123)
; routines2(44,uw+123)
;
; routine(uw+123, 22,33, true, 44)
; routine2(uw+123, 22,33, true, 44)
test_stack.test()