ast mutable to prepare for expression rewriting

This commit is contained in:
Irmen de Jong 2018-08-11 15:19:25 +02:00
parent 112e05dc84
commit 89ffb0021d
2 changed files with 140 additions and 125 deletions

View File

@ -1,10 +1,34 @@
package il65 package il65
import il65.ast.Label
import il65.ast.LiteralValue
import il65.ast.PrefixExpression
import il65.ast.toAst import il65.ast.toAst
import il65.parser.il65Lexer import il65.parser.il65Lexer
import il65.parser.il65Parser import il65.parser.il65Parser
import org.antlr.v4.runtime.CharStreams import org.antlr.v4.runtime.CharStreams
import org.antlr.v4.runtime.CommonTokenStream import org.antlr.v4.runtime.CommonTokenStream
import org.antlr.v4.runtime.Lexer
import org.antlr.v4.runtime.misc.IntegerList
class MyTokenStream(lexer: Lexer) : CommonTokenStream(lexer) {
data class Comment(val type: String, val line: Int, val comment: String)
fun commentTokens() : List<Comment> {
// extract the comments
val commentTokenChannel = il65Lexer.channelNames.indexOf("HIDDEN")
val theLexer = tokenSource as Lexer
return get(0, size())
.filter { it.channel == commentTokenChannel }
.map {
Comment(theLexer.vocabulary.getSymbolicName(it.type),
it.line, it.text.substringAfter(';').trim())
}
}
}
fun main(args: Array<String>) { fun main(args: Array<String>) {
@ -13,7 +37,7 @@ fun main(args: Array<String>) {
val input = CharStreams.fromString( val input = CharStreams.fromString(
"%zp clobber,derp,33,de\n" + "%zp clobber,derp,33,de\n" +
"~ main \$c000 { \n" + "~ main \$c000 { \n" +
" A=4 to 99\n" + " A=4 + 99\n" +
" ; full position comment\n" + " ; full position comment\n" +
" %asm {{\n" + " %asm {{\n" +
" position 1\n"+ " position 1\n"+
@ -23,26 +47,17 @@ fun main(args: Array<String>) {
"}\n" "}\n"
) )
val lexer = il65Lexer(input) val lexer = il65Lexer(input)
val tokens = CommonTokenStream(lexer) val tokens = MyTokenStream(lexer)
val parser = il65Parser(tokens) val parser = il65Parser(tokens)
val module = parser.module() val module = parser.module()
val program = module.toAst(true) val program = module.toAst(true)
println(tokens.size()) // the comments:
val commentTokenChannel = il65Lexer.channelNames.indexOf("HIDDEN") tokens.commentTokens().forEach { println(it) }
tokens.get(0, tokens.size()).filter{it.channel==commentTokenChannel}.map{
val comment = it.text.substringAfter(';').trim()
when(lexer.vocabulary.getSymbolicName(it.type)) {
"COMMENT" -> println("comment at ${it.line}: >>$comment<<")
"LINECOMMENT" -> println("position comment at ${it.line}: >>$comment<<")
else -> throw UnsupportedOperationException("comment token type ${it.type}")
}
}
program.lines.map { program.lines.map {
println(it) println(it)
} }
} }

View File

@ -30,137 +30,141 @@ enum class Register {
data class Position(val line: Int, val startCol:Int, val endCol: Int) data class Position(val line: Int, val startCol:Int, val endCol: Int)
interface Node interface Node {
{ val position: Position? // optional for the sake of easy unit testing
val position: Position
} }
interface IStatement : Node interface IStatement : Node
data class Module(val lines: List<IStatement>, data class Module(val lines: MutableList<IStatement>,
override val position: Position) : Node override val position: Position? = null) : Node
data class Block(val name: String, val address: Int?, val statements: List<IStatement>, data class Block(val name: String, val address: Int?, val statements: MutableList<IStatement>,
override val position: Position) : IStatement override val position: Position? = null) : IStatement
data class Directive(val directive: String, val args: List<DirectiveArg>, data class Directive(val directive: String, val args: List<DirectiveArg>,
override val position: Position) : IStatement override val position: Position? = null) : IStatement
data class DirectiveArg(val str: String?, val name: String?, val int: Int?, data class DirectiveArg(val str: String?, val name: String?, val int: Int?,
override val position: Position) : Node override val position: Position? = null) : Node
data class Label(val name: String, data class Label(val name: String,
override val position: Position) : IStatement override val position: Position? = null) : IStatement
interface IVarDecl : IStatement { interface IVarDecl : IStatement {
val datatype: DataType val datatype: DataType
val arrayspec: ArraySpec? val arrayspec: ArraySpec?
val name: String val name: String
val value: IExpression? var value: IExpression?
} }
data class ArraySpec(val x: IExpression, val y: IExpression?, data class ArraySpec(var x: IExpression,
override val position: Position) : Node var y: IExpression?,
override val position: Position? = null) : Node
data class VarDecl(override val datatype: DataType, data class VarDecl(override val datatype: DataType,
override val arrayspec: ArraySpec?, override val arrayspec: ArraySpec?,
override val name: String, override val name: String,
override val value: IExpression?, override var value: IExpression?,
override val position: Position) : IVarDecl override val position: Position? = null) : IVarDecl
data class ConstDecl(override val datatype: DataType, data class ConstDecl(override val datatype: DataType,
override val arrayspec: ArraySpec?, override val arrayspec: ArraySpec?,
override val name: String, override val name: String,
override val value: IExpression, override var value: IExpression?,
override val position: Position) : IVarDecl override val position: Position? = null) : IVarDecl
data class MemoryVarDecl(override val datatype: DataType, data class MemoryVarDecl(override val datatype: DataType,
override val arrayspec: ArraySpec?, override val arrayspec: ArraySpec?,
override val name: String, override val name: String,
override val value: IExpression, override var value: IExpression?,
override val position: Position) : IVarDecl override val position: Position? = null) : IVarDecl
data class Assignment(val target: AssignTarget, val aug_op : String?, val value: IExpression, data class Assignment(val target: AssignTarget, val aug_op : String?, var value: IExpression,
override val position: Position) : IStatement override val position: Position? = null) : IStatement
data class AssignTarget(val register: Register?, val identifier: Identifier?, data class AssignTarget(val register: Register?, val identifier: Identifier?,
override val position: Position) : Node override val position: Position? = null) : Node
interface IExpression: Node interface IExpression: Node
data class PrefixExpression(val operator: String, val expression: IExpression,
override val position: Position) : IExpression
data class BinaryExpression(val left: IExpression, val operator: String, val right: IExpression, // note: some expression elements are mutable, to be able to rewrite/optimize the expression tree
override val position: Position) : IExpression
data class PrefixExpression(val operator: String, val expression: IExpression,
override val position: Position? = null) : IExpression
data class BinaryExpression(var left: IExpression, val operator: String, var right: IExpression,
override val position: Position? = null) : IExpression
data class LiteralValue(val intvalue: Int?, data class LiteralValue(val intvalue: Int?,
val floatvalue: Double?, val floatvalue: Double?,
val strvalue: String?, val strvalue: String?,
val boolvalue: Boolean?, val boolvalue: Boolean?,
val arrayvalue: List<IExpression>?, val arrayvalue: MutableList<IExpression>?,
override val position: Position) : IExpression override val position: Position? = null) : IExpression
data class RangeExpr(val from: IExpression, val to: IExpression, data class RangeExpr(var from: IExpression, var to: IExpression,
override val position: Position) : IExpression override val position: Position? = null) : IExpression
data class RegisterExpr(val register: Register, data class RegisterExpr(val register: Register,
override val position: Position) : IExpression override val position: Position? = null) : IExpression
data class Identifier(val name: String, val scope: List<String>, data class Identifier(val name: String, val scope: List<String>,
override val position: Position) : IExpression override val position: Position? = null) : IExpression
data class CallTarget(val address: Int?, val identifier: Identifier?, data class CallTarget(val address: Int?, val identifier: Identifier?,
override val position: Position) : Node override val position: Position? = null) : Node
data class PostIncrDecr(val target: AssignTarget, val operator: String, data class PostIncrDecr(val target: AssignTarget, val operator: String,
override val position: Position) : IStatement override val position: Position? = null) : IStatement
data class Jump(val target: CallTarget, data class Jump(val target: CallTarget,
override val position: Position) : IStatement override val position: Position? = null) : IStatement
data class FunctionCall(val target: CallTarget, val arglist: List<IExpression>, data class FunctionCall(val target: CallTarget, val arglist: MutableList<IExpression>,
override val position: Position) : IExpression override val position: Position? = null) : IExpression
data class InlineAssembly(val assembly: String, data class InlineAssembly(val assembly: String,
override val position: Position) : IStatement override val position: Position? = null) : IStatement
/***************** Antlr Extension methods to create AST ****************/ /***************** Antlr Extension methods to create AST ****************/
fun ParserRuleContext.toPosition(withPosition: Boolean) : Position { fun ParserRuleContext.toPosition(withPosition: Boolean) : Position? {
return if (withPosition) return if (withPosition)
Position(start.line, start.charPositionInLine, stop.charPositionInLine) Position(start.line, start.charPositionInLine, stop.charPositionInLine)
else else
Position(start.line, start.charPositionInLine, stop.charPositionInLine) // @todo null null
} }
fun il65Parser.ModuleContext.toAst(withPosition: Boolean) = fun il65Parser.ModuleContext.toAst(withPosition: Boolean) =
Module(this.modulestatement().map { it.toAst(withPosition) }, Module(modulestatement().map { it.toAst(withPosition) }.toMutableList(), toPosition(withPosition))
this.toPosition(withPosition))
fun il65Parser.ModulestatementContext.toAst(withPosition: Boolean) : IStatement { fun il65Parser.ModulestatementContext.toAst(withPosition: Boolean) : IStatement {
val directive = this.directive()?.toAst(withPosition) val directive = directive()?.toAst(withPosition)
if(directive!=null) return directive if(directive!=null) return directive
val block = this.block()?.toAst(withPosition) val block = block()?.toAst(withPosition)
if(block!=null) return block if(block!=null) return block
throw UnsupportedOperationException(this.text) throw UnsupportedOperationException(text)
} }
fun il65Parser.BlockContext.toAst(withPosition: Boolean) : IStatement { fun il65Parser.BlockContext.toAst(withPosition: Boolean) : IStatement {
return Block(this.identifier().text, this.integerliteral()?.toAst(), return Block(identifier().text,
this.statement().map { it.toAst(withPosition) }, this.toPosition(withPosition)) integerliteral()?.toAst(),
statement().map { it.toAst(withPosition) }.toMutableList(),
toPosition(withPosition))
} }
fun il65Parser.StatementContext.toAst(withPosition: Boolean) : IStatement { fun il65Parser.StatementContext.toAst(withPosition: Boolean) : IStatement {
val vardecl = this.vardecl() val vardecl = vardecl()
if(vardecl!=null) { if(vardecl!=null) {
return VarDecl(vardecl.datatype().toAst(), return VarDecl(vardecl.datatype().toAst(),
vardecl.arrayspec()?.toAst(withPosition), vardecl.arrayspec()?.toAst(withPosition),
@ -169,7 +173,7 @@ fun il65Parser.StatementContext.toAst(withPosition: Boolean) : IStatement {
vardecl.toPosition(withPosition)) vardecl.toPosition(withPosition))
} }
val varinit = this.varinitializer() val varinit = varinitializer()
if(varinit!=null) { if(varinit!=null) {
return VarDecl(varinit.datatype().toAst(), return VarDecl(varinit.datatype().toAst(),
varinit.arrayspec()?.toAst(withPosition), varinit.arrayspec()?.toAst(withPosition),
@ -178,7 +182,7 @@ fun il65Parser.StatementContext.toAst(withPosition: Boolean) : IStatement {
varinit.toPosition(withPosition)) varinit.toPosition(withPosition))
} }
val constdecl = this.constdecl() val constdecl = constdecl()
if(constdecl!=null) { if(constdecl!=null) {
val cvarinit = constdecl.varinitializer() val cvarinit = constdecl.varinitializer()
return ConstDecl(cvarinit.datatype().toAst(), return ConstDecl(cvarinit.datatype().toAst(),
@ -188,7 +192,7 @@ fun il65Parser.StatementContext.toAst(withPosition: Boolean) : IStatement {
cvarinit.toPosition(withPosition)) cvarinit.toPosition(withPosition))
} }
val memdecl = this.memoryvardecl() val memdecl = memoryvardecl()
if(memdecl!=null) { if(memdecl!=null) {
val mvarinit = memdecl.varinitializer() val mvarinit = memdecl.varinitializer()
return MemoryVarDecl(mvarinit.datatype().toAst(), return MemoryVarDecl(mvarinit.datatype().toAst(),
@ -198,41 +202,41 @@ fun il65Parser.StatementContext.toAst(withPosition: Boolean) : IStatement {
mvarinit.toPosition(withPosition)) mvarinit.toPosition(withPosition))
} }
val assign = this.assignment() val assign = assignment()
if (assign!=null) { if (assign!=null) {
return Assignment(assign.assign_target().toAst(withPosition), return Assignment(assign.assign_target().toAst(withPosition),
null, assign.expression().toAst(withPosition), null, assign.expression().toAst(withPosition),
assign.toPosition(withPosition)) assign.toPosition(withPosition))
} }
val augassign = this.augassignment() val augassign = augassignment()
if (augassign!=null) if (augassign!=null)
return Assignment(augassign.assign_target().toAst(withPosition), return Assignment(augassign.assign_target().toAst(withPosition),
augassign.operator.text, augassign.operator.text,
augassign.expression().toAst(withPosition), augassign.expression().toAst(withPosition),
augassign.toPosition(withPosition)) augassign.toPosition(withPosition))
val post = this.postincrdecr() val post = postincrdecr()
if(post!=null) if(post!=null)
return PostIncrDecr(post.assign_target().toAst(withPosition), return PostIncrDecr(post.assign_target().toAst(withPosition),
post.operator.text, post.toPosition(withPosition)) post.operator.text, post.toPosition(withPosition))
val directive = this.directive()?.toAst(withPosition) val directive = directive()?.toAst(withPosition)
if(directive!=null) return directive if(directive!=null) return directive
val label=this.label() val label=label()
if(label!=null) if(label!=null)
return Label(label.text, label.toPosition(withPosition)) return Label(label.text, label.toPosition(withPosition))
val jump = this.unconditionaljump() val jump = unconditionaljump()
if(jump!=null) if(jump!=null)
return Jump(jump.call_location().toAst(withPosition), jump.toPosition(withPosition)) return Jump(jump.call_location().toAst(withPosition), jump.toPosition(withPosition))
val asm = this.inlineasm() val asm = inlineasm()
if(asm!=null) if(asm!=null)
return InlineAssembly(asm.INLINEASMBLOCK().text, asm.toPosition(withPosition)) return InlineAssembly(asm.INLINEASMBLOCK().text, asm.toPosition(withPosition))
throw UnsupportedOperationException(this.text) throw UnsupportedOperationException(text)
} }
@ -247,55 +251,53 @@ fun il65Parser.Call_locationContext.toAst(withPosition: Boolean) : CallTarget {
fun il65Parser.Assign_targetContext.toAst(withPosition: Boolean) : AssignTarget { fun il65Parser.Assign_targetContext.toAst(withPosition: Boolean) : AssignTarget {
val register = this.register()?.toAst() val register = register()?.toAst()
val identifier = this.identifier() val identifier = identifier()
return if(identifier!=null) return if(identifier!=null)
AssignTarget(register, identifier.toAst(withPosition), this.toPosition(withPosition)) AssignTarget(register, identifier.toAst(withPosition), toPosition(withPosition))
else else
AssignTarget(register, this.scoped_identifier()?.toAst(withPosition), this.toPosition(withPosition)) AssignTarget(register, scoped_identifier()?.toAst(withPosition), toPosition(withPosition))
} }
fun il65Parser.RegisterContext.toAst() = Register.valueOf(this.text.toUpperCase()) fun il65Parser.RegisterContext.toAst() = Register.valueOf(text.toUpperCase())
fun il65Parser.DatatypeContext.toAst() = DataType.valueOf(this.text.toUpperCase()) fun il65Parser.DatatypeContext.toAst() = DataType.valueOf(text.toUpperCase())
fun il65Parser.ArrayspecContext.toAst(withPosition: Boolean) = ArraySpec( fun il65Parser.ArrayspecContext.toAst(withPosition: Boolean) = ArraySpec(
this.expression(0).toAst(withPosition), expression(0).toAst(withPosition),
if (this.expression().size > 1) this.expression(1).toAst(withPosition) else null, if (expression().size > 1) expression(1).toAst(withPosition) else null,
this.toPosition(withPosition) toPosition(withPosition)
) )
fun il65Parser.DirectiveContext.toAst(withPosition: Boolean) = fun il65Parser.DirectiveContext.toAst(withPosition: Boolean) =
Directive(this.directivename.text, Directive(directivename.text, directivearg().map { it.toAst(withPosition) }, toPosition(withPosition))
this.directivearg().map { it.toAst(withPosition) },
this.toPosition(withPosition))
fun il65Parser.DirectiveargContext.toAst(withPosition: Boolean) = fun il65Parser.DirectiveargContext.toAst(withPosition: Boolean) =
DirectiveArg(this.stringliteral()?.text, DirectiveArg(stringliteral()?.text,
this.identifier()?.text, identifier()?.text,
this.integerliteral()?.toAst(), integerliteral()?.toAst(),
this.toPosition(withPosition)) toPosition(withPosition))
fun il65Parser.IntegerliteralContext.toAst(): Int { fun il65Parser.IntegerliteralContext.toAst(): Int {
val terminal: TerminalNode = this.children[0] as TerminalNode val terminal: TerminalNode = children[0] as TerminalNode
return when (terminal.symbol.type) { return when (terminal.symbol.type) {
il65Parser.DEC_INTEGER -> this.text.toInt() il65Parser.DEC_INTEGER -> text.toInt()
il65Parser.HEX_INTEGER -> this.text.substring(1).toInt(16) il65Parser.HEX_INTEGER -> text.substring(1).toInt(16)
il65Parser.BIN_INTEGER -> this.text.substring(1).toInt(2) il65Parser.BIN_INTEGER -> text.substring(1).toInt(2)
else -> throw UnsupportedOperationException(this.text) else -> throw UnsupportedOperationException(text)
} }
} }
fun il65Parser.ExpressionContext.toAst(withPosition: Boolean) : IExpression { fun il65Parser.ExpressionContext.toAst(withPosition: Boolean) : IExpression {
val litval = this.literalvalue() val litval = literalvalue()
if(litval!=null) if(litval!=null)
return LiteralValue(litval.integerliteral()?.toAst(), return LiteralValue(litval.integerliteral()?.toAst(),
litval.floatliteral()?.toAst(), litval.floatliteral()?.toAst(),
@ -305,67 +307,65 @@ fun il65Parser.ExpressionContext.toAst(withPosition: Boolean) : IExpression {
litval.toPosition(withPosition) litval.toPosition(withPosition)
) )
if(this.register()!=null) if(register()!=null)
return RegisterExpr(this.register().toAst(), this.register().toPosition(withPosition)) return RegisterExpr(register().toAst(), register().toPosition(withPosition))
if(this.identifier()!=null) if(identifier()!=null)
return this.identifier().toAst(withPosition) return identifier().toAst(withPosition)
if(this.scoped_identifier()!=null) if(scoped_identifier()!=null)
return this.scoped_identifier().toAst(withPosition) return scoped_identifier().toAst(withPosition)
if(this.bop!=null) if(bop!=null)
return BinaryExpression(this.left.toAst(withPosition), return BinaryExpression(left.toAst(withPosition),
this.bop.text, bop.text,
this.right.toAst(withPosition), right.toAst(withPosition),
this.toPosition(withPosition)) toPosition(withPosition))
if(this.prefix!=null) if(prefix!=null)
return PrefixExpression(this.prefix.text, return PrefixExpression(prefix.text,
this.expression(0).toAst(withPosition), expression(0).toAst(withPosition),
this.toPosition(withPosition)) toPosition(withPosition))
val funcall = this.functioncall() val funcall = functioncall()
if(funcall!=null) { if(funcall!=null) {
val location = funcall.call_location().toAst(withPosition) val location = funcall.call_location().toAst(withPosition)
return if(funcall.expression()!=null) return if(funcall.expression()!=null)
FunctionCall(location, listOf(funcall.expression().toAst(withPosition)), funcall.toPosition(withPosition)) FunctionCall(location, mutableListOf(funcall.expression().toAst(withPosition)), funcall.toPosition(withPosition))
else else
FunctionCall(location, emptyList(), funcall.toPosition(withPosition)) FunctionCall(location, mutableListOf(), funcall.toPosition(withPosition))
} }
if (this.rangefrom!=null && this.rangeto!=null) if (rangefrom!=null && rangeto!=null)
return RangeExpr(this.rangefrom.toAst(withPosition), return RangeExpr(rangefrom.toAst(withPosition), rangeto.toAst(withPosition), toPosition(withPosition))
this.rangeto.toAst(withPosition),
this.toPosition(withPosition))
throw UnsupportedOperationException(this.text) throw UnsupportedOperationException(text)
} }
fun il65Parser.IdentifierContext.toAst(withPosition: Boolean) : Identifier { fun il65Parser.IdentifierContext.toAst(withPosition: Boolean) : Identifier {
return Identifier(this.text, emptyList(), this.toPosition(withPosition)) return Identifier(text, emptyList(), toPosition(withPosition))
} }
fun il65Parser.Scoped_identifierContext.toAst(withPosition: Boolean) : Identifier { fun il65Parser.Scoped_identifierContext.toAst(withPosition: Boolean) : Identifier {
val names = this.NAME() val names = NAME()
val name = names.last().text val name = names.last().text
val scope = names.take(names.size-1) val scope = names.take(names.size-1)
return Identifier(name, scope.map { it.text }, toPosition(withPosition)) return Identifier(name, scope.map { it.text }, toPosition(withPosition))
} }
fun il65Parser.FloatliteralContext.toAst() = this.text.toDouble() fun il65Parser.FloatliteralContext.toAst() = text.toDouble()
fun il65Parser.BooleanliteralContext.toAst() = when(this.text) { fun il65Parser.BooleanliteralContext.toAst() = when(text) {
"true" -> true "true" -> true
"false" -> false "false" -> false
else -> throw UnsupportedOperationException(this.text) else -> throw UnsupportedOperationException(text)
} }
fun il65Parser.ArrayliteralContext.toAst(withPosition: Boolean) = fun il65Parser.ArrayliteralContext.toAst(withPosition: Boolean) =
this.expression().map { it.toAst(withPosition) } expression().map { it.toAst(withPosition) }.toMutableList()