mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 01:29:28 +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.
|
||||
As any subroutine, it has to end with a ``return`` statement (or a ``goto`` call)::
|
||||
|
||||
~ main {
|
||||
sub start () -> () {
|
||||
; program entrypoint code here
|
||||
return
|
||||
}
|
||||
}
|
||||
~ main {
|
||||
sub start () -> () {
|
||||
; program entrypoint code here
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
The ``main`` module is always relocated to the start of your programs
|
||||
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.
|
||||
|
||||
|
||||
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
|
||||
$aa43 ; hex integer number
|
||||
%100101 ; binary integer number
|
||||
"Hi, I am a string" ; text string
|
||||
-33.456e52 ; floating point number
|
||||
|
||||
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
|
||||
^^^^^^^^
|
||||
|
||||
|
@ -136,14 +136,15 @@ Directives
|
||||
Identifiers
|
||||
-----------
|
||||
|
||||
Naming things in IL65 is done via valid *identifiers*. They start with a letter, and after that,
|
||||
must consist of letters, numbers, or underscores. Examples of valid identifiers::
|
||||
Naming things in IL65 is done via valid *identifiers*. They start with a letter or underscore,
|
||||
and after that, a combination of letters, numbers, or underscores. Examples of valid identifiers::
|
||||
|
||||
a
|
||||
A
|
||||
monkey
|
||||
COUNTER
|
||||
Better_Name_2
|
||||
_something_strange_
|
||||
|
||||
|
||||
Code blocks
|
||||
@ -246,6 +247,25 @@ type identifier type storage size example var declara
|
||||
|
||||
**@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
|
||||
^^^^^^^^^^^^^^
|
||||
|
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
|
||||
|
||||
PROJECT=~/Projects/IL65/antlr
|
||||
PROJECT=~/Projects/IL65/il65/antlr
|
||||
|
||||
export CLASSPATH=".:${PROJECT}/lib/antlr-4.7.1-complete.jar:${CLASSPATH}"
|
||||
java -jar ${PROJECT}/lib/antlr-4.7.1-complete.jar $*
|
@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
PROJECT=~/Projects/IL65/antlr
|
||||
PROJECT=~/Projects/IL65/il65/antlr
|
||||
|
||||
export CLASSPATH=".:${PROJECT}/lib/antlr-4.7.1-complete.jar:${CLASSPATH}"
|
||||
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;
|
||||
|
||||
|
||||
program
|
||||
: line*
|
||||
EOF
|
||||
;
|
||||
|
||||
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