mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
grammar
This commit is contained in:
parent
cee0f5bd2a
commit
437c948c05
@ -135,12 +135,12 @@ The compiler expects a ``start`` subroutine in the ``main`` block for this,
|
|||||||
taking no parameters and having no return value.
|
taking no parameters and having no return value.
|
||||||
As any subroutine, it has to end with a ``return`` statement (or a ``goto`` call)::
|
As any subroutine, it has to end with a ``return`` statement (or a ``goto`` call)::
|
||||||
|
|
||||||
~ main {
|
~ main {
|
||||||
sub start () -> () {
|
sub start () -> () {
|
||||||
; program entrypoint code here
|
; program entrypoint code here
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
The ``main`` module is always relocated to the start of your programs
|
The ``main`` module is always relocated to the start of your programs
|
||||||
address space, and the ``start`` subroutine (the entrypoint) will be on the
|
address space, and the ``start`` subroutine (the entrypoint) will be on the
|
||||||
@ -148,18 +148,39 @@ first address. This will also be the address that the BASIC loader program (if g
|
|||||||
calls with the SYS statement.
|
calls with the SYS statement.
|
||||||
|
|
||||||
|
|
||||||
Variables and data
|
Variables and values
|
||||||
------------------
|
--------------------
|
||||||
|
|
||||||
::
|
Variables are named values that can change during the execution of the program.
|
||||||
|
When declaring a variable it is possible to specify the initial value it should get.
|
||||||
|
Values will usually be part of an expression or assignment statement::
|
||||||
|
|
||||||
12345 ; integer number
|
12345 ; integer number
|
||||||
|
$aa43 ; hex integer number
|
||||||
|
%100101 ; binary integer number
|
||||||
"Hi, I am a string" ; text string
|
"Hi, I am a string" ; text string
|
||||||
-33.456e52 ; floating point number
|
-33.456e52 ; floating point number
|
||||||
|
|
||||||
byte counter = 42 ; variable of size 8 bits, with initial value 42
|
byte counter = 42 ; variable of size 8 bits, with initial value 42
|
||||||
|
|
||||||
|
|
||||||
|
Special types: const and memory-mapped
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
When using ``const``, the value of the 'variable' can no longer be changed.
|
||||||
|
You'll have to specify the initial value expression. This value is then used
|
||||||
|
by the compiler everywhere you refer to the constant (and no storage is allocated
|
||||||
|
for the constant itself).
|
||||||
|
|
||||||
|
When using ``memory``, the variable will point to specific location in memory,
|
||||||
|
rather than being newly allocated. The initial value (mandatory) must be a valid
|
||||||
|
memory address. Reading the variable will read the given data type from the
|
||||||
|
address you specified, and setting the varible will directly modify that memory location(s)::
|
||||||
|
|
||||||
|
const byte max_age = 2000 - 1974 ; max_age will be the constant value 26
|
||||||
|
memory word SCREENCOLORS = $d020 ; a 16-bit word at the addres $d020-$d021
|
||||||
|
|
||||||
|
|
||||||
Integers
|
Integers
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
|
|
||||||
|
@ -136,14 +136,15 @@ Directives
|
|||||||
Identifiers
|
Identifiers
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Naming things in IL65 is done via valid *identifiers*. They start with a letter, and after that,
|
Naming things in IL65 is done via valid *identifiers*. They start with a letter or underscore,
|
||||||
must consist of letters, numbers, or underscores. Examples of valid identifiers::
|
and after that, a combination of letters, numbers, or underscores. Examples of valid identifiers::
|
||||||
|
|
||||||
a
|
a
|
||||||
A
|
A
|
||||||
monkey
|
monkey
|
||||||
COUNTER
|
COUNTER
|
||||||
Better_Name_2
|
Better_Name_2
|
||||||
|
_something_strange_
|
||||||
|
|
||||||
|
|
||||||
Code blocks
|
Code blocks
|
||||||
@ -246,6 +247,25 @@ type identifier type storage size example var declara
|
|||||||
|
|
||||||
**@todo signed integers (byte and word)?**
|
**@todo signed integers (byte and word)?**
|
||||||
|
|
||||||
|
Memory mapped variables
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The ``memory`` keyword is used in front of a data type keyword, to say that no storage
|
||||||
|
should be allocated by the compiler. Instead, the value assigned to the variable (mandatory now!)
|
||||||
|
should be the *memory address* where the value is located::
|
||||||
|
|
||||||
|
memory byte BORDER = $d020
|
||||||
|
|
||||||
|
|
||||||
|
Constants
|
||||||
|
^^^^^^^^^
|
||||||
|
|
||||||
|
All variables can be assigned new values unless you use the ``const`` keyword.
|
||||||
|
The initial value will now be evaluated at compile time (it must be a compile time constant expression)
|
||||||
|
and no storage is allocated for the constant::
|
||||||
|
|
||||||
|
const byte max_age = 99
|
||||||
|
|
||||||
|
|
||||||
Reserved names
|
Reserved names
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
3
il65/antlr/Makefile
Normal file
3
il65/antlr/Makefile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
parser:
|
||||||
|
./antlr.sh -o ../src/net/razorvine/il65/parser -listener -visitor -package net.razorvine.il65.parser tinybasic.g4
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
PROJECT=~/Projects/IL65/antlr
|
PROJECT=~/Projects/IL65/il65/antlr
|
||||||
|
|
||||||
export CLASSPATH=".:${PROJECT}/lib/antlr-4.7.1-complete.jar:${CLASSPATH}"
|
export CLASSPATH=".:${PROJECT}/lib/antlr-4.7.1-complete.jar:${CLASSPATH}"
|
||||||
java -jar ${PROJECT}/lib/antlr-4.7.1-complete.jar $*
|
java -jar ${PROJECT}/lib/antlr-4.7.1-complete.jar $*
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
PROJECT=~/Projects/IL65/antlr
|
PROJECT=~/Projects/IL65/il65/antlr
|
||||||
|
|
||||||
export CLASSPATH=".:${PROJECT}/lib/antlr-4.7.1-complete.jar:${CLASSPATH}"
|
export CLASSPATH=".:${PROJECT}/lib/antlr-4.7.1-complete.jar:${CLASSPATH}"
|
||||||
java org.antlr.v4.gui.TestRig $*
|
java org.antlr.v4.gui.TestRig $*
|
113
il65/antlr/il65.g4
Normal file
113
il65/antlr/il65.g4
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
IL65 lexer and parser grammar
|
||||||
|
*/
|
||||||
|
|
||||||
|
grammar il65;
|
||||||
|
|
||||||
|
|
||||||
|
NAME : [a-zA-Z_][a-zA-Z0-9_]* ;
|
||||||
|
DEC_INTEGER : ('0'..'9') | (('1'..'9')('0'..'9')+);
|
||||||
|
HEX_INTEGER : '$' (('a'..'f') | ('A'..'F') | ('0'..'9'))+ ;
|
||||||
|
BIN_INTEGER : '%' ('0' | '1')+ ;
|
||||||
|
|
||||||
|
|
||||||
|
module :
|
||||||
|
line*
|
||||||
|
EOF
|
||||||
|
;
|
||||||
|
|
||||||
|
line :
|
||||||
|
directive
|
||||||
|
| vardecl
|
||||||
|
| assignment
|
||||||
|
| augassignment
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
directive :
|
||||||
|
'%' singlename (literalvalue)?
|
||||||
|
;
|
||||||
|
|
||||||
|
vardecl:
|
||||||
|
datatype arrayspec? singlename ('=' expression)?
|
||||||
|
;
|
||||||
|
|
||||||
|
datatype:
|
||||||
|
'byte' | 'word' | 'float' | 'str' | 'str_p' | 'str_s' | 'str_ps'
|
||||||
|
;
|
||||||
|
|
||||||
|
arrayspec:
|
||||||
|
'[' expression (',' expression)? ']'
|
||||||
|
;
|
||||||
|
|
||||||
|
assignment :
|
||||||
|
assign_target '=' expression
|
||||||
|
;
|
||||||
|
|
||||||
|
augassignment :
|
||||||
|
assign_target ('+=' | '-=' | '/=' | '//=' | '*=' | '**=' |
|
||||||
|
'<<=' | '>>=' | '<<@=' | '>>@=' | '&=' | '|=' | '^=') expression
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
expression :
|
||||||
|
unary_expression
|
||||||
|
| '(' expression ')'
|
||||||
|
| expression '**' expression
|
||||||
|
| expression ('*' | '/' | '//' | '**') expression
|
||||||
|
| expression ('+' | '-' | '%') expression
|
||||||
|
| expression ('<<' | '>>' | '<<@' | '>>@' | '&' | '|' | '^') expression
|
||||||
|
| expression ('and' | 'or' | 'xor') expression
|
||||||
|
| expression ('==' | '!=' | '<' | '>' | '<=' | '>=') expression
|
||||||
|
| literalvalue
|
||||||
|
| register
|
||||||
|
| dottedname
|
||||||
|
| singlename
|
||||||
|
;
|
||||||
|
|
||||||
|
unary_expression:
|
||||||
|
'~' expression
|
||||||
|
| ('+' | '-') expression
|
||||||
|
| 'not' expression
|
||||||
|
;
|
||||||
|
|
||||||
|
singlename:
|
||||||
|
NAME
|
||||||
|
;
|
||||||
|
|
||||||
|
dottedname:
|
||||||
|
NAME ('.' NAME)+
|
||||||
|
;
|
||||||
|
|
||||||
|
register:
|
||||||
|
'A' | 'X' | 'Y' | 'AX' | 'AY' | 'XY' | 'SC' | 'SI' | 'SZ'
|
||||||
|
;
|
||||||
|
|
||||||
|
literalvalue:
|
||||||
|
BIN_INTEGER | HEX_INTEGER | DEC_INTEGER
|
||||||
|
| 'true' | 'false'
|
||||||
|
| array
|
||||||
|
;
|
||||||
|
|
||||||
|
array:
|
||||||
|
'[' expression (',' expression)* ']'
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
assign_target:
|
||||||
|
register
|
||||||
|
| singlename
|
||||||
|
| dottedname
|
||||||
|
;
|
||||||
|
|
||||||
|
COMMENT :
|
||||||
|
';' ~[\r\n]* -> channel(1)
|
||||||
|
;
|
||||||
|
|
||||||
|
WS :
|
||||||
|
[ \t] -> skip
|
||||||
|
;
|
||||||
|
|
||||||
|
EOL :
|
||||||
|
[\r\n]+ -> skip
|
||||||
|
;
|
@ -28,8 +28,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
grammar tinybasic;
|
grammar tinybasic;
|
||||||
|
|
||||||
|
|
||||||
program
|
program
|
||||||
: line*
|
: line*
|
||||||
|
EOF
|
||||||
;
|
;
|
||||||
|
|
||||||
line
|
line
|
13
il65/il65.iml
Normal file
13
il65/il65.iml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="lib" level="project" />
|
||||||
|
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
70
il65/src/AST.kt
Normal file
70
il65/src/AST.kt
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package il65.ast
|
||||||
|
|
||||||
|
import net.razorvine.il65.parser.tinybasicParser
|
||||||
|
|
||||||
|
interface Node
|
||||||
|
interface Statement : Node
|
||||||
|
|
||||||
|
data class Program(val lines: List<Line>) : Node
|
||||||
|
data class Line(val number: Int?, val statement: Statement) : Node
|
||||||
|
|
||||||
|
data class Print(val exprlist: List<Expression>) : Statement
|
||||||
|
data class If(val expression1: Expression, val relop: Char, val expression2: Expression, val then: Statement) : Statement
|
||||||
|
data class Goto(val number: Int) : Statement
|
||||||
|
data class Input(val varlist: List<Var>) : Statement
|
||||||
|
data class Let(val vara: Var, val expression: Expression) : Statement
|
||||||
|
data class Gosub(val expression: Expression): Statement
|
||||||
|
class Return: Statement
|
||||||
|
class Clear : Statement
|
||||||
|
class ListStmt : Statement
|
||||||
|
class Run : Statement
|
||||||
|
class End : Statement
|
||||||
|
|
||||||
|
data class TermListTerm(val operator: Char, val term: Term) : Node
|
||||||
|
data class FactorListFactor(val operator: Char, val factor: Factor) : Node
|
||||||
|
data class Expression(val unaryOp: Char?, val term: Term, val terms: List<TermListTerm>) : Node
|
||||||
|
data class Term(val factor: Factor, val factors: List<FactorListFactor>) : Node
|
||||||
|
data class Factor(val thing: String) : Node
|
||||||
|
data class Var(val thing: String): Node
|
||||||
|
|
||||||
|
|
||||||
|
fun tinybasicParser.ProgramContext.toAst(): Program = Program(this.line().map {
|
||||||
|
Line(it.number().toAst(), it.statement().toAst())
|
||||||
|
})
|
||||||
|
|
||||||
|
fun tinybasicParser.NumberContext.toAst(): Int = this.DIGIT().joinToString(separator = "").toInt()
|
||||||
|
|
||||||
|
fun tinybasicParser.StatementContext.toAst(): Statement =
|
||||||
|
when (this.children[0].text) {
|
||||||
|
"INPUT" -> Input(this.varlist().toAst())
|
||||||
|
"IF" -> If(this.expression(0).toAst(), this.relop().toAst(), this.expression(1).toAst(), this.statement().toAst())
|
||||||
|
"PRINT" -> Print(this.exprlist().toAst())
|
||||||
|
"GOTO" -> Goto(this.number().toAst())
|
||||||
|
"LET" -> Let(this.vara().toAst(), this.expression(0).toAst())
|
||||||
|
"GOSUB" -> Gosub(this.expression(0).toAst())
|
||||||
|
"RETURN" -> Return()
|
||||||
|
"CLEAR" -> Clear()
|
||||||
|
"LIST" -> ListStmt()
|
||||||
|
"RUN" -> Run()
|
||||||
|
"END" -> End()
|
||||||
|
else -> Let(this.vara().toAst(), this.expression(0).toAst())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tinybasicParser.RelopContext.toAst() : Char = this.text[0]
|
||||||
|
|
||||||
|
fun tinybasicParser.VarlistContext.toAst() : List<Var> {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tinybasicParser.ExprlistContext.toAst() : List<Expression> {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tinybasicParser.VaraContext.toAst() : Var = Var(this.text)
|
||||||
|
|
||||||
|
fun tinybasicParser.ExpressionContext.toAst() : Expression {
|
||||||
|
val unaryOp = '+'
|
||||||
|
val term = Term(Factor("derp"), emptyList())
|
||||||
|
return Expression(unaryOp, term, emptyList())
|
||||||
|
}
|
||||||
|
|
20
il65/src/Main.kt
Normal file
20
il65/src/Main.kt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package il65
|
||||||
|
|
||||||
|
import il65.ast.*
|
||||||
|
import net.razorvine.il65.parser.tinybasicLexer
|
||||||
|
import net.razorvine.il65.parser.tinybasicParser
|
||||||
|
import org.antlr.v4.runtime.CharStreams
|
||||||
|
import org.antlr.v4.runtime.CommonTokenStream
|
||||||
|
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
println("Reading source file: ${args[0]}")
|
||||||
|
val input = CharStreams.fromFileName(args[0])
|
||||||
|
val lexer = tinybasicLexer(input)
|
||||||
|
val tokens = CommonTokenStream(lexer)
|
||||||
|
val parser = tinybasicParser(tokens)
|
||||||
|
val parseTree: tinybasicParser.ProgramContext = parser.program()
|
||||||
|
val program = parseTree.toAst()
|
||||||
|
println(program)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user