mirror of
https://github.com/irmen/prog8.git
synced 2025-01-11 13:29:45 +00:00
various syntax checks added
first steps code generation
This commit is contained in:
parent
e928997193
commit
8ef61ffc88
@ -101,8 +101,7 @@ The name of a block must be unique in your entire program.
|
||||
Also be careful when importing other modules; blocks in your own code cannot have
|
||||
the same name as a block defined in an imported module or library.
|
||||
|
||||
It's possible to omit this name, but then you can only refer to the contents of the block via its absolute address,
|
||||
which is required in this case. If you omit *both* name and address, the block is *ignored* by the compiler (and a warning is displayed).
|
||||
If you omit both the name and address, the entire block is *ignored* by the compiler (and a warning is displayed).
|
||||
This is a way to quickly "comment out" a piece of code that is unfinshed or may contain errors that you
|
||||
want to work on later, because the contents of the ignored block are not fully parsed either.
|
||||
|
||||
|
@ -15,15 +15,18 @@
|
||||
const byte snerp2 = snerp+22
|
||||
|
||||
X = 42+snerp
|
||||
return 44+snerp
|
||||
;return 44+snerp
|
||||
return
|
||||
|
||||
sub foo234234() -> () {
|
||||
A=99+snerp
|
||||
return A+snerp2
|
||||
;return A+snerp2
|
||||
return
|
||||
}
|
||||
|
||||
sub thingy()->() {
|
||||
return 99
|
||||
;return 99
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +35,7 @@
|
||||
; this is imported
|
||||
|
||||
X = 42
|
||||
return 44
|
||||
;return 44
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,12 @@
|
||||
const byte equal = 4==4
|
||||
const byte equal2 = (4+hopla)>0
|
||||
|
||||
goto 64738
|
||||
|
||||
; A++
|
||||
derp++
|
||||
cc2--
|
||||
|
||||
goto mega
|
||||
if_eq goto mega
|
||||
|
||||
@ -81,6 +87,7 @@
|
||||
byte equalQQ = 4==4
|
||||
const byte equalQQ2 = (4+hopla)>0
|
||||
|
||||
sin(1) ; @todo error statement has no effect (returnvalue of builtin function not used)
|
||||
P_carry(1)
|
||||
P_irqd(0)
|
||||
|
||||
@ -145,21 +152,24 @@ cool:
|
||||
sub foo () -> () {
|
||||
byte blerp = 3
|
||||
A=99
|
||||
return 33
|
||||
; return 33
|
||||
return
|
||||
ultrafoo()
|
||||
X =33
|
||||
mega:
|
||||
cool:
|
||||
sub ultrafoo() -> () {
|
||||
X= extra233.thingy()
|
||||
return 33
|
||||
;return 33
|
||||
return
|
||||
goto main.mega
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
some_label_def: A=44
|
||||
return 1+999
|
||||
;return 1+999
|
||||
return
|
||||
%breakpoint
|
||||
%asminclude "derp", hopsa
|
||||
%asmbinary "derp", 0, 200
|
||||
|
@ -54,16 +54,16 @@ fun main(args: Array<String>) {
|
||||
StatementReorderer().process(moduleAst) // reorder statements to please the compiler later
|
||||
val globalNamespaceAfterOptimize = moduleAst.definingScope() // create it again, it could have changed in the meantime
|
||||
moduleAst.checkValid(globalNamespaceAfterOptimize, compilerOptions) // check if final tree is valid
|
||||
moduleAst.checkRecursion() // check if there are recursive subroutine calls
|
||||
moduleAst.checkRecursion(globalNamespaceAfterOptimize) // check if there are recursive subroutine calls
|
||||
|
||||
// globalNamespaceAfterOptimize.debugPrint()
|
||||
|
||||
// compile the syntax tree into intermediate form, and optimize that
|
||||
// compile the syntax tree into stackvmProg form, and optimize that
|
||||
val compiler = Compiler(compilerOptions)
|
||||
val intermediate = compiler.compile(moduleAst)
|
||||
intermediate.optimize()
|
||||
|
||||
// val assembly = intermediate.compileToAssembly()
|
||||
// val assembly = stackvmProg.compileToAssembly()
|
||||
//
|
||||
// assembly.assemble(compilerOptions, "input", "output")
|
||||
// val monitorfile = assembly.generateBreakpointList()
|
||||
|
@ -172,6 +172,11 @@ interface IAstProcessor {
|
||||
assignment.value = assignment.value.process(this)
|
||||
return assignment
|
||||
}
|
||||
|
||||
fun process(postIncrDecr: PostIncrDecr): IStatement {
|
||||
postIncrDecr.target = postIncrDecr.target.process(this)
|
||||
return postIncrDecr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -226,9 +231,9 @@ interface IStatement : Node {
|
||||
interface IFunctionCall {
|
||||
var target: IdentifierReference
|
||||
var arglist: List<IExpression>
|
||||
var targetStatement: IStatement
|
||||
}
|
||||
|
||||
|
||||
interface INameScope {
|
||||
val name: String
|
||||
val position: Position?
|
||||
@ -387,7 +392,7 @@ private class GlobalNamespace(override val name: String,
|
||||
is Subroutine -> stmt.scopedname
|
||||
else -> throw NameError("wrong identifier target: $stmt", stmt.position)
|
||||
}
|
||||
registerUsedName(targetScopedName.joinToString("."))
|
||||
registerUsedName(targetScopedName)
|
||||
}
|
||||
return stmt
|
||||
}
|
||||
@ -406,7 +411,8 @@ class Block(override val name: String,
|
||||
override var statements: MutableList<IStatement>) : IStatement, INameScope {
|
||||
override var position: Position? = null
|
||||
override lateinit var parent: Node
|
||||
val scopedname: List<String> by lazy { makeScopedName(name) }
|
||||
val scopedname: String by lazy { makeScopedName(name).joinToString(".") }
|
||||
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
@ -450,7 +456,7 @@ data class DirectiveArg(val str: String?, val name: String?, val int: Int?) : No
|
||||
data class Label(val name: String) : IStatement {
|
||||
override var position: Position? = null
|
||||
override lateinit var parent: Node
|
||||
val scopedname: List<String> by lazy { makeScopedName(name) }
|
||||
val scopedname: String by lazy { makeScopedName(name).joinToString(".") }
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
@ -477,6 +483,10 @@ class Return(var values: List<IExpression>) : IStatement {
|
||||
values = values.map { it.process(processor) }
|
||||
return this
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Return(values: $values, pos=$position)"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -532,7 +542,8 @@ class VarDecl(val type: VarDeclType,
|
||||
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
|
||||
val scopedname: List<String> by lazy { makeScopedName(name) }
|
||||
val scopedname: String by lazy { makeScopedName(name).joinToString(".") }
|
||||
|
||||
|
||||
fun arraySizeX(namespace: INameScope) : Int? {
|
||||
return arrayspec?.x?.constValue(namespace)?.intvalue
|
||||
@ -558,6 +569,10 @@ class Assignment(var target: AssignTarget, val aug_op : String?, var value: IExp
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
|
||||
override fun toString(): String {
|
||||
return("Assignment(augop: $aug_op, target: $target, value: $value, pos=$position)")
|
||||
}
|
||||
}
|
||||
|
||||
data class AssignTarget(val register: Register?, val identifier: IdentifierReference?) : Node {
|
||||
@ -700,11 +715,16 @@ data class IdentifierReference(val nameInSource: List<String>) : IExpression {
|
||||
override var position: Position? = null
|
||||
override lateinit var parent: Node
|
||||
|
||||
fun targetStatement(namespace: INameScope) =
|
||||
if(nameInSource.size==1 && BuiltinFunctionNames.contains(nameInSource[0]))
|
||||
BuiltinFunctionStatementPlaceholder
|
||||
else
|
||||
namespace.lookup(nameInSource, this)
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
}
|
||||
|
||||
|
||||
override fun constValue(namespace: INameScope): LiteralValue? {
|
||||
val node = namespace.lookup(nameInSource, this)
|
||||
?: throw UndefinedSymbolException(this)
|
||||
@ -735,9 +755,10 @@ class PostIncrDecr(var target: AssignTarget, val operator: String) : IStatement
|
||||
target.linkParents(this)
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor): IStatement {
|
||||
target = target.process(processor)
|
||||
return this
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
|
||||
override fun toString(): String {
|
||||
return "PostIncrDecr(op: $operator, target: $target, pos=$position)"
|
||||
}
|
||||
}
|
||||
|
||||
@ -745,7 +766,6 @@ class PostIncrDecr(var target: AssignTarget, val operator: String) : IStatement
|
||||
class Jump(val address: Int?, val identifier: IdentifierReference?) : IStatement {
|
||||
override var position: Position? = null
|
||||
override lateinit var parent: Node
|
||||
var targetStatement: IStatement? = null
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
@ -753,13 +773,16 @@ class Jump(val address: Int?, val identifier: IdentifierReference?) : IStatement
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
|
||||
override fun toString(): String {
|
||||
return "Jump(addr: $address, identifier: $identifier, target: pos=$position)"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class FunctionCall(override var target: IdentifierReference, override var arglist: List<IExpression>) : IExpression, IFunctionCall {
|
||||
override var position: Position? = null
|
||||
override lateinit var parent: Node
|
||||
override lateinit var targetStatement: IStatement
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
@ -825,7 +848,6 @@ class FunctionCall(override var target: IdentifierReference, override var arglis
|
||||
class FunctionCallStatement(override var target: IdentifierReference, override var arglist: List<IExpression>) : IStatement, IFunctionCall {
|
||||
override var position: Position? = null
|
||||
override lateinit var parent: Node
|
||||
override lateinit var targetStatement: IStatement
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
@ -860,7 +882,8 @@ class Subroutine(override val name: String,
|
||||
override var statements: MutableList<IStatement>) : IStatement, INameScope {
|
||||
override var position: Position? = null
|
||||
override lateinit var parent: Node
|
||||
val scopedname: List<String> by lazy { makeScopedName(name) }
|
||||
val scopedname: String by lazy { makeScopedName(name).joinToString(".") }
|
||||
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
@ -930,6 +953,10 @@ class BranchStatement(var condition: BranchCondition,
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor): IStatement = processor.process(this)
|
||||
|
||||
override fun toString(): String {
|
||||
return "Branch(cond: $condition, ${statements.size} stmts, ${elsepart.size} else-stmts, pos=$position)"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -53,8 +53,10 @@ class AstChecker(private val globalNamespace: INameScope, private val compilerOp
|
||||
override fun process(jump: Jump): IStatement {
|
||||
if(jump.identifier!=null) {
|
||||
val targetStatement = checkFunctionOrLabelExists(jump.identifier, jump)
|
||||
if(targetStatement!=null)
|
||||
jump.targetStatement = targetStatement // link to actual jump target
|
||||
if(targetStatement!=null) {
|
||||
if(targetStatement is BuiltinFunctionStatementPlaceholder)
|
||||
checkResult.add(SyntaxError("can't jump to a builtin function", jump.position))
|
||||
}
|
||||
}
|
||||
|
||||
if(jump.address!=null && (jump.address < 0 || jump.address > 65535))
|
||||
@ -303,28 +305,38 @@ class AstChecker(private val globalNamespace: INameScope, private val compilerOp
|
||||
?: throw FatalAstException("cannot determine statement scope of function call expression at ${functionCall.position}")
|
||||
|
||||
val targetStatement = checkFunctionOrLabelExists(functionCall.target, stmtOfExpression)
|
||||
if(targetStatement!=null) {
|
||||
functionCall.targetStatement = targetStatement // link to the actual target statement
|
||||
if(targetStatement!=null)
|
||||
checkBuiltinFunctionCall(functionCall, functionCall.position)
|
||||
}
|
||||
return super.process(functionCall)
|
||||
}
|
||||
|
||||
override fun process(functionCall: FunctionCallStatement): IStatement {
|
||||
val targetStatement = checkFunctionOrLabelExists(functionCall.target, functionCall)
|
||||
if(targetStatement!=null) {
|
||||
functionCall.targetStatement = targetStatement // link to the actual target statement
|
||||
if(targetStatement!=null)
|
||||
checkBuiltinFunctionCall(functionCall, functionCall.position)
|
||||
}
|
||||
return super.process(functionCall)
|
||||
}
|
||||
|
||||
private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: IStatement): IStatement? {
|
||||
if(target.nameInSource.size==1 && BuiltinFunctionNames.contains(target.nameInSource[0])) {
|
||||
return BuiltinFunctionStatementPlaceholder
|
||||
override fun process(postIncrDecr: PostIncrDecr): IStatement {
|
||||
if(postIncrDecr.target.register==null) {
|
||||
val targetName = postIncrDecr.target.identifier!!.nameInSource
|
||||
val target = globalNamespace.lookup(targetName, postIncrDecr)
|
||||
if(target==null) {
|
||||
checkResult.add(SyntaxError("undefined symbol: ${targetName.joinToString(".")}", postIncrDecr.position))
|
||||
} else {
|
||||
if(target !is VarDecl || target.type==VarDeclType.CONST) {
|
||||
checkResult.add(SyntaxError("can only increment or decrement a variable", postIncrDecr.position))
|
||||
} else if(target.datatype!=DataType.FLOAT && target.datatype!=DataType.WORD && target.datatype!=DataType.BYTE) {
|
||||
checkResult.add(SyntaxError("can only increment or decrement a byte/float/word variable", postIncrDecr.position))
|
||||
}
|
||||
}
|
||||
}
|
||||
val targetStatement = globalNamespace.lookup(target.nameInSource, statement)
|
||||
if(targetStatement is Label || targetStatement is Subroutine)
|
||||
return super.process(postIncrDecr)
|
||||
}
|
||||
|
||||
private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: IStatement): IStatement? {
|
||||
val targetStatement = target.targetStatement(globalNamespace)
|
||||
if(targetStatement is Label || targetStatement is Subroutine || targetStatement is BuiltinFunctionStatementPlaceholder)
|
||||
return targetStatement
|
||||
checkResult.add(SyntaxError("undefined function or subroutine: ${target.nameInSource.joinToString(".")}", statement.position))
|
||||
return null
|
||||
|
@ -36,7 +36,7 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
}
|
||||
|
||||
override fun process(block: Block): IStatement {
|
||||
val scopedName = block.scopedname.joinToString(".")
|
||||
val scopedName = block.scopedname
|
||||
val existing = symbols[scopedName]
|
||||
if(existing!=null) {
|
||||
nameError(block.name, block.position, existing)
|
||||
@ -51,7 +51,7 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
// the builtin functions can't be redefined
|
||||
checkResult.add(NameError("builtin function cannot be redefined", decl.position))
|
||||
|
||||
val scopedName = decl.scopedname.joinToString(".")
|
||||
val scopedName = decl.scopedname
|
||||
val existing = symbols[scopedName]
|
||||
if(existing!=null) {
|
||||
nameError(decl.name, decl.position, existing)
|
||||
@ -66,7 +66,7 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
// the builtin functions can't be redefined
|
||||
checkResult.add(NameError("builtin function cannot be redefined", subroutine.position))
|
||||
} else {
|
||||
val scopedName = subroutine.scopedname.joinToString(".")
|
||||
val scopedName = subroutine.scopedname
|
||||
val existing = symbols[scopedName]
|
||||
if (existing != null) {
|
||||
nameError(subroutine.name, subroutine.position, existing)
|
||||
@ -82,7 +82,7 @@ class AstIdentifiersChecker : IAstProcessor {
|
||||
// the builtin functions can't be redefined
|
||||
checkResult.add(NameError("builtin function cannot be redefined", label.position))
|
||||
} else {
|
||||
val scopedName = label.scopedname.joinToString(".")
|
||||
val scopedName = label.scopedname
|
||||
val existing = symbols[scopedName]
|
||||
if (existing != null) {
|
||||
nameError(label.name, label.position, existing)
|
||||
|
@ -6,8 +6,8 @@ import il65.parser.ParsingFailedError
|
||||
* Checks for the occurrence of recursive subroutine calls
|
||||
*/
|
||||
|
||||
fun Module.checkRecursion() {
|
||||
val checker = AstRecursionChecker()
|
||||
fun Module.checkRecursion(namespace: INameScope) {
|
||||
val checker = AstRecursionChecker(namespace)
|
||||
this.process(checker)
|
||||
val checkResult = checker.result()
|
||||
checkResult.forEach {
|
||||
@ -88,7 +88,7 @@ class DirectedGraph<VT> {
|
||||
}
|
||||
|
||||
|
||||
class AstRecursionChecker : IAstProcessor {
|
||||
class AstRecursionChecker(val namespace: INameScope) : IAstProcessor {
|
||||
private val callGraph = DirectedGraph<INameScope>()
|
||||
|
||||
fun result(): List<AstException> {
|
||||
@ -96,26 +96,32 @@ class AstRecursionChecker : IAstProcessor {
|
||||
if(cycle.isEmpty())
|
||||
return emptyList()
|
||||
val chain = cycle.joinToString(" <-- ") { "${it.name} at ${it.position}" }
|
||||
return listOf(AstException("Program contains recursive subroutine calls, this is not supported. Recursive chain:\n"+chain))
|
||||
return listOf(AstException("Program contains recursive subroutine calls, this is not supported. Recursive chain:\n (a subroutine call in) "+chain))
|
||||
}
|
||||
|
||||
override fun process(functionCall: FunctionCallStatement): IStatement {
|
||||
val scope = functionCall.definingScope()
|
||||
val targetScope = when(functionCall.targetStatement) {
|
||||
is Subroutine -> functionCall.targetStatement as Subroutine
|
||||
else -> functionCall.targetStatement.definingScope()
|
||||
val targetStatement = functionCall.target.targetStatement(namespace)
|
||||
if(targetStatement!=null) {
|
||||
val targetScope = when (targetStatement) {
|
||||
is Subroutine -> targetStatement
|
||||
else -> targetStatement.definingScope()
|
||||
}
|
||||
callGraph.add(scope, targetScope)
|
||||
}
|
||||
callGraph.add(scope, targetScope)
|
||||
return super.process(functionCall)
|
||||
}
|
||||
|
||||
override fun process(functionCall: FunctionCall): IExpression {
|
||||
val scope = functionCall.definingScope()
|
||||
val targetScope = when(functionCall.targetStatement) {
|
||||
is Subroutine -> functionCall.targetStatement as Subroutine
|
||||
else -> functionCall.targetStatement.definingScope()
|
||||
val targetStatement = functionCall.target.targetStatement(namespace)
|
||||
if(targetStatement!=null) {
|
||||
val targetScope = when (targetStatement) {
|
||||
is Subroutine -> targetStatement
|
||||
else -> targetStatement.definingScope()
|
||||
}
|
||||
callGraph.add(scope, targetScope)
|
||||
}
|
||||
callGraph.add(scope, targetScope)
|
||||
return super.process(functionCall)
|
||||
}
|
||||
}
|
||||
|
@ -85,38 +85,227 @@ data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, va
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
; source code for a stackvm program
|
||||
; init memory bytes/words/strings
|
||||
%memory
|
||||
0400 01 02 03 04 05 06 07 08 09 22 33 44 55 66
|
||||
0500 1111 2222 3333 4444
|
||||
1000 "Hello world!\n"
|
||||
%end_memory
|
||||
; init global var table with bytes/words/floats/strings
|
||||
%variables
|
||||
main.var1 str "This is main.var1"
|
||||
main.var2 byte aa
|
||||
main.var3 word ea44
|
||||
main.var4 float 3.1415927
|
||||
input.prompt str "Enter a number: "
|
||||
input.result word 0
|
||||
%end_variables
|
||||
; instructions and labels
|
||||
%instructions
|
||||
nop
|
||||
syscall WRITE_MEMSTR word:1000
|
||||
loop:
|
||||
syscall WRITE_VAR str:"input.prompt"
|
||||
syscall INPUT_VAR str:"input.result"
|
||||
syscall WRITE_VAR str:"input.result"
|
||||
push byte:8d
|
||||
syscall WRITE_CHAR
|
||||
jump loop
|
||||
%end_instructions
|
||||
|
||||
|
||||
*/
|
||||
|
||||
class Compiler(private val options: CompilationOptions) {
|
||||
fun compile(module: Module) : IntermediateForm {
|
||||
println("\nCompiling parsed source code to intermediate code...")
|
||||
|
||||
// todo
|
||||
fun compile(module: Module) : StackVmProgram {
|
||||
println("\nCompiling parsed source code to stackvmProg code...")
|
||||
|
||||
val namespace = module.definingScope()
|
||||
|
||||
// todo
|
||||
val intermediate = StackVmProgram(module.name)
|
||||
namespace.debugPrint()
|
||||
|
||||
module.statements.filter { it is Block }.map {
|
||||
with(it as Block) {
|
||||
"$address $scopedname"
|
||||
|
||||
// create the pool of all variables used in all blocks and scopes
|
||||
val varGather = VarGatherer(intermediate)
|
||||
varGather.process(module)
|
||||
|
||||
val stmtGatherer = StatementGatherer(intermediate, namespace)
|
||||
stmtGatherer.process(module)
|
||||
|
||||
intermediate.toTextLines().forEach { System.out.println(it) }
|
||||
return intermediate
|
||||
}
|
||||
|
||||
|
||||
class VarGatherer(val stackvmProg: StackVmProgram): IAstProcessor {
|
||||
// collect all the VarDecls to make them into one global list
|
||||
override fun process(decl: VarDecl): IStatement {
|
||||
assert(decl.type==VarDeclType.VAR) {"only VAR decls should remain: CONST and MEMORY should have been processed away"}
|
||||
stackvmProg.blockvar(decl.scopedname, decl)
|
||||
return super.process(decl)
|
||||
}
|
||||
}
|
||||
|
||||
class StatementGatherer(val stackvmProg: StackVmProgram, val namespace: INameScope): IAstProcessor {
|
||||
override fun process(subroutine: Subroutine): IStatement {
|
||||
translate(subroutine.statements)
|
||||
return super.process(subroutine)
|
||||
}
|
||||
|
||||
override fun process(block: Block): IStatement {
|
||||
translate(block.statements)
|
||||
return super.process(block)
|
||||
}
|
||||
|
||||
private fun translate(statements: List<IStatement>) {
|
||||
for (stmt: IStatement in statements) {
|
||||
when (stmt) {
|
||||
is AnonymousStatementList -> translate(stmt.statements)
|
||||
is BuiltinFunctionStatementPlaceholder -> translate(stmt)
|
||||
is Label -> translate(stmt)
|
||||
is Return -> translate(stmt)
|
||||
is Assignment -> translate(stmt)
|
||||
is PostIncrDecr -> translate(stmt)
|
||||
is Jump -> translate(stmt)
|
||||
is FunctionCallStatement -> translate(stmt)
|
||||
is InlineAssembly -> translate(stmt)
|
||||
is IfStatement -> translate(stmt)
|
||||
is BranchStatement -> translate(stmt)
|
||||
is Directive, is VarDecl, is Subroutine -> {}
|
||||
else -> TODO("translate statement $stmt")
|
||||
}
|
||||
}
|
||||
}.forEach { println(it) }
|
||||
return IntermediateForm(module.name)
|
||||
}
|
||||
|
||||
private fun translate(stmt: BranchStatement) {
|
||||
println("translate: $stmt")
|
||||
// todo
|
||||
}
|
||||
|
||||
private fun translate(stmt: IfStatement) {
|
||||
println("translate: $stmt")
|
||||
// todo
|
||||
}
|
||||
|
||||
private fun translate(stmt: InlineAssembly) {
|
||||
println("translate: $stmt")
|
||||
TODO("inline assembly not supported yet by stackvm")
|
||||
}
|
||||
|
||||
private fun translate(stmt: FunctionCallStatement) {
|
||||
println("translate: $stmt")
|
||||
// todo
|
||||
}
|
||||
|
||||
private fun translate(stmt: Jump) {
|
||||
val instr =
|
||||
if(stmt.address!=null) {
|
||||
"jump \$${stmt.address.toString(16)}"
|
||||
} else {
|
||||
val target = stmt.identifier!!.targetStatement(namespace)!!
|
||||
when(target) {
|
||||
is Label -> "jump ${target.scopedname}"
|
||||
is Subroutine -> "jump ${target.scopedname}"
|
||||
else -> throw CompilerException("invalid jump target type ${target::class}")
|
||||
}
|
||||
}
|
||||
stackvmProg.instruction(instr)
|
||||
}
|
||||
|
||||
private fun translate(stmt: PostIncrDecr) {
|
||||
if(stmt.target.register!=null) {
|
||||
TODO("register++/-- not yet implemented")
|
||||
} else {
|
||||
val targetStatement = stmt.target.identifier!!.targetStatement(namespace) as VarDecl
|
||||
when(stmt.operator) {
|
||||
"++" -> stackvmProg.instruction("inc_var ${targetStatement.scopedname}")
|
||||
"--" -> stackvmProg.instruction("decr_var ${targetStatement.scopedname}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun translate(stmt: Assignment) {
|
||||
println("translate: $stmt")
|
||||
// todo
|
||||
}
|
||||
|
||||
private fun translate(stmt: Return) {
|
||||
if(stmt.values.isNotEmpty()) {
|
||||
TODO("return with value(s) not yet supported: $stmt")
|
||||
}
|
||||
stackvmProg.instruction("return")
|
||||
}
|
||||
|
||||
private fun translate(stmt: Label) {
|
||||
stackvmProg.label(stmt.scopedname)
|
||||
}
|
||||
|
||||
private fun translate(stmt: BuiltinFunctionStatementPlaceholder) {
|
||||
println("translate: $stmt")
|
||||
// todo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class IntermediateForm(val name: String) {
|
||||
|
||||
class StackVmProgram(val name: String) {
|
||||
|
||||
val variables = mutableMapOf<String, VarDecl>()
|
||||
val instructions = mutableListOf<String>()
|
||||
|
||||
fun optimize() {
|
||||
println("\nOptimizing intermediate code...")
|
||||
println("\nOptimizing stackvmProg code...")
|
||||
// todo
|
||||
}
|
||||
|
||||
fun compileToAssembly(): AssemblyResult {
|
||||
println("\nGenerating assembly code from intermediate code... ")
|
||||
println("\nGenerating assembly code from stackvmProg code... ")
|
||||
// todo
|
||||
return AssemblyResult(name)
|
||||
}
|
||||
|
||||
fun blockvar(scopedname: String, decl: VarDecl) {
|
||||
println("$scopedname $decl")
|
||||
variables[scopedname] = decl
|
||||
}
|
||||
|
||||
fun toTextLines() : List<String> {
|
||||
val result = mutableListOf("; stackvm program code for: $name")
|
||||
result.add("%memory")
|
||||
// todo memory lines for initial memory initialization
|
||||
result.add("%end_memory")
|
||||
result.add("%variables")
|
||||
for(v in variables) {
|
||||
assert(v.value.type==VarDeclType.VAR || v.value.type==VarDeclType.CONST)
|
||||
val litval = v.value.value as LiteralValue
|
||||
val litvalStr = when {
|
||||
litval.isNumeric -> litval.asNumericValue.toString()
|
||||
litval.isString -> "\"${litval.strvalue}\""
|
||||
else -> TODO()
|
||||
}
|
||||
val line = "${v.key} ${v.value.datatype.toString().toLowerCase()} $litvalStr"
|
||||
result.add(line)
|
||||
}
|
||||
result.add("%end_variables")
|
||||
result.add("%instructions")
|
||||
result.addAll(instructions)
|
||||
result.add("%end_nstructions")
|
||||
return result
|
||||
}
|
||||
|
||||
fun instruction(s: String) {
|
||||
instructions.add(" $s")
|
||||
}
|
||||
|
||||
fun label(name: String) {
|
||||
instructions.add("$name:")
|
||||
}
|
||||
}
|
||||
|
||||
enum class OutputType {
|
||||
|
@ -83,7 +83,7 @@ class StatementOptimizer(private val globalNamespace: INameScope) : IAstProcesso
|
||||
is Subroutine -> stmt.scopedname
|
||||
else -> throw AstException("invalid call target node type: ${stmt::class}")
|
||||
}
|
||||
globalNamespace.registerUsedName(scopedName.joinToString("."))
|
||||
globalNamespace.registerUsedName(scopedName)
|
||||
}
|
||||
|
||||
fun removeUnusedNodes(usedNames: Set<String>, allScopedSymbolDefinitions: MutableMap<String, IStatement>) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user