mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-03 19:31:02 +00:00
Allow semicolons in certain positions. Partially implements #6
This commit is contained in:
parent
e19ac75350
commit
e9990dc9c1
@ -10,6 +10,9 @@ For information about assembly, see [Using assembly within Millfork programs](./
|
||||
|
||||
Comments start with `//` and last until the end of line.
|
||||
|
||||
Inside assembly blocks, including assembly functions, you can alternatively start comments with `;`.
|
||||
Such comments cannot contain braces.
|
||||
|
||||
## Declarations
|
||||
|
||||
|
||||
@ -220,6 +223,12 @@ All starting modules are considered to be imported by all source files explicitl
|
||||
|
||||
## Statements
|
||||
|
||||
Statements are separated from each other with a new line, or with a semicolon followed by a new line.
|
||||
|
||||
You cannot put two statements on one line.
|
||||
|
||||
In statement blocks, the opening and closing braces do not need to be separated from the statements.
|
||||
|
||||
### Expression statement
|
||||
|
||||
TODO
|
||||
|
@ -399,7 +399,7 @@ abstract class MfParser[T](fileId: String, input: String, currentDirectory: Stri
|
||||
|
||||
def statement: P[Seq[Statement]] = (position() ~ P(keywordStatement | arrayDefinition | localVariableDefinition | expressionStatement)).map { case (p, s) => s.map(_.pos(p)) }
|
||||
|
||||
def asmStatements: P[List[ExecutableStatement]] = ("{" ~/ AWS ~/ asmStatement.rep(sep = NoCut(EOL) ~ !"}" ~/ Pass) ~/ AWS ~/ "}" ~/ Pass).map(_.toList)
|
||||
def asmStatements: P[List[ExecutableStatement]] = ("{" ~/ AWS_asm ~/ asmStatement.rep(sep = NoCut(EOL_asm) ~ !"}" ~/ Pass) ~/ AWS_asm ~/ "}" ~/ Pass).map(_.toList)
|
||||
|
||||
def statements: P[List[Statement]] = ("{" ~/ AWS ~ statement.rep(sep = NoCut(EOL) ~ !"}" ~/ Pass) ~/ AWS ~/ "}" ~/ Pass).map(_.flatten.toList)
|
||||
|
||||
@ -587,15 +587,23 @@ object MfParser {
|
||||
|
||||
val comment: P[Unit] = P("//" ~/ CharsWhile(c => c != '\n' && c != '\r', min = 0) ~ ("\r\n" | "\r" | "\n"))
|
||||
|
||||
val semicolon: P[Unit] = P(";" ~/ CharsWhileIn("; \t", min = 0) ~ (comment | "\r\n" | "\r" | "\n"))
|
||||
|
||||
val semicolonComment: P[Unit] = P(";" ~/ CharsWhile(c => c != '\n' && c != '\r' && c != '{' && c != '}', min = 0) ~ ("\r\n" | "\r" | "\n"))
|
||||
|
||||
val SWS: P[Unit] = P(CharsWhileIn(" \t", min = 1)).opaque("<horizontal whitespace>")
|
||||
|
||||
val HWS: P[Unit] = P(CharsWhileIn(" \t", min = 0)).opaque("<horizontal whitespace>")
|
||||
|
||||
val AWS: P[Unit] = P((CharIn(" \t\n\r;") | NoCut(comment)).rep(min = 0)).opaque("<any whitespace>")
|
||||
val AWS: P[Unit] = P((CharIn(" \t\n\r") | NoCut(semicolon) | NoCut(comment)).rep(min = 0)).opaque("<any whitespace>")
|
||||
|
||||
val EOL: P[Unit] = P(HWS ~ ("\r\n" | "\r" | "\n" | comment).opaque("<first line break>") ~ AWS).opaque("<line break>")
|
||||
val AWS_asm: P[Unit] = P((CharIn(" \t\n\r") | NoCut(semicolonComment) | NoCut(comment)).rep(min = 0)).opaque("<any whitespace>")
|
||||
|
||||
val EOLOrComma: P[Unit] = P(HWS ~ ("\r\n" | "\r" | "\n" | "," | comment).opaque("<first line break or comma>") ~ AWS).opaque("<line break or comma>")
|
||||
val EOL: P[Unit] = P(HWS ~ ("\r\n" | "\r" | "\n" | semicolon | comment).opaque("<first line break>") ~ AWS).opaque("<line break>")
|
||||
|
||||
val EOL_asm: P[Unit] = P(HWS ~ ("\r\n" | "\r" | "\n" | comment | semicolonComment).opaque("<first line break>") ~ AWS).opaque("<line break>")
|
||||
|
||||
val EOLOrComma: P[Unit] = P(HWS ~ ("\r\n" | "\r" | "\n" | "," | semicolon | comment).opaque("<first line break or comma>") ~ AWS).opaque("<line break or comma>")
|
||||
|
||||
val letter: P[String] = P(CharIn("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_").!)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package millfork.test
|
||||
import millfork.test.emu.{EmuBenchmarkRun, EmuOptimizedCmosRun, EmuOptimizedRun}
|
||||
import millfork.Cpu
|
||||
import millfork.test.emu.{EmuBenchmarkRun, EmuCrossPlatformBenchmarkRun, EmuOptimizedCmosRun, EmuOptimizedRun}
|
||||
import org.scalatest.{AppendedClues, FunSuite, Matchers}
|
||||
|
||||
/**
|
||||
@ -8,13 +9,13 @@ import org.scalatest.{AppendedClues, FunSuite, Matchers}
|
||||
class AssemblySuite extends FunSuite with Matchers with AppendedClues {
|
||||
|
||||
test("Inline assembly") {
|
||||
EmuBenchmarkRun(
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Motorola6809)(
|
||||
"""
|
||||
| byte output @$c000
|
||||
| void main () {
|
||||
| output = 0
|
||||
| asm {
|
||||
| inc $c000
|
||||
| inc $c000 ; this is an assembly-style comment
|
||||
| }
|
||||
| }
|
||||
""".stripMargin)(_.readByte(0xc000) should equal(1))
|
||||
|
@ -1,7 +1,7 @@
|
||||
package millfork.test
|
||||
|
||||
import millfork.Cpu
|
||||
import millfork.test.emu.{EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedRun}
|
||||
import millfork.test.emu.{EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedRun, ShouldNotParse}
|
||||
import org.scalatest.{FunSuite, Matchers}
|
||||
|
||||
/**
|
||||
@ -53,9 +53,9 @@ class BasicSymonTest extends FunSuite with Matchers {
|
||||
output += 1
|
||||
output += 1
|
||||
output += 1
|
||||
output += 1
|
||||
output += 1
|
||||
output += 1
|
||||
output += 1 ;
|
||||
output += 1 ;;
|
||||
output += 1 ; //comment
|
||||
output += 1
|
||||
output += 1
|
||||
output += 1
|
||||
@ -254,4 +254,41 @@ class BasicSymonTest extends FunSuite with Matchers {
|
||||
m.readByte(0xc000) should equal(1)
|
||||
}
|
||||
}
|
||||
|
||||
test("Semicolon syntax test") {
|
||||
ShouldNotParse(
|
||||
"""
|
||||
|void main() {
|
||||
| a ; b
|
||||
|}
|
||||
|""".stripMargin)
|
||||
ShouldNotParse(
|
||||
"""
|
||||
|void main() {
|
||||
| asm { ; }
|
||||
|}
|
||||
|""".stripMargin)
|
||||
ShouldNotParse(
|
||||
"""
|
||||
|void main() {
|
||||
| nop ; do absolutely nothing{}
|
||||
|}
|
||||
|""".stripMargin)
|
||||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
|
||||
"""
|
||||
|byte a,b
|
||||
|void main() {
|
||||
| a=b; // test
|
||||
| b=a
|
||||
| }
|
||||
|""".stripMargin){_=>}
|
||||
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
|
||||
"""
|
||||
| void main() {
|
||||
| asm { ;hello
|
||||
| nop ; do absolutely nothing
|
||||
| }
|
||||
| }
|
||||
|""".stripMargin){_=>}
|
||||
}
|
||||
}
|
||||
|
49
src/test/scala/millfork/test/emu/ShouldNotParse.scala
Normal file
49
src/test/scala/millfork/test/emu/ShouldNotParse.scala
Normal file
@ -0,0 +1,49 @@
|
||||
package millfork.test.emu
|
||||
|
||||
import fastparse.core.Parsed.{Failure, Success}
|
||||
import millfork.compiler.LabelGenerator
|
||||
import millfork.parser._
|
||||
import millfork._
|
||||
import org.scalatest.Matchers
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
*/
|
||||
object ShouldNotParse extends Matchers {
|
||||
def apply(source: String): Unit = {
|
||||
checkCase(Cpu.Mos, source)
|
||||
checkCase(Cpu.Z80, source)
|
||||
checkCase(Cpu.Motorola6809, source)
|
||||
}
|
||||
|
||||
private def checkCase(cpu: Cpu.Value, source: String) {
|
||||
Console.out.flush()
|
||||
Console.err.flush()
|
||||
val log = TestErrorReporting.log
|
||||
println(source)
|
||||
val platform = EmuPlatform.get(cpu)
|
||||
val options = CompilationOptions(platform, Map(CompilationFlag.LenientTextEncoding -> true), None, platform.zpRegisterSize, Map(), JobContext(log, new LabelGenerator))
|
||||
log.hasErrors = false
|
||||
log.verbosity = 999
|
||||
var effectiveSource = source
|
||||
log.setSource(Some(effectiveSource.linesIterator.toIndexedSeq))
|
||||
val PreprocessingResult(preprocessedSource, features, _) = Preprocessor.preprocessForTest(options, effectiveSource)
|
||||
val parserF =
|
||||
platform.cpuFamily match {
|
||||
case CpuFamily.M6502 =>
|
||||
MosParser("", preprocessedSource, "", options, features)
|
||||
case CpuFamily.M6809 =>
|
||||
M6809Parser("", preprocessedSource, "", options, features)
|
||||
case CpuFamily.I80 =>
|
||||
Z80Parser("", preprocessedSource, "", options, features, options.flag(CompilationFlag.UseIntelSyntaxForInput))
|
||||
}
|
||||
parserF.toAst match {
|
||||
case Success(program, _) =>
|
||||
fail("Parse succeded")
|
||||
case f: Failure[_, _] =>
|
||||
println(f.extra.toString)
|
||||
println(f.lastParser.toString)
|
||||
log.info("Expected syntax error: " + parserF.lastLabel, Some(parserF.lastPosition))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user