Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip/Ignore/Optional parts #34

Open
rabbitfr opened this issue Nov 25, 2020 · 1 comment
Open

Skip/Ignore/Optional parts #34

rabbitfr opened this issue Nov 25, 2020 · 1 comment

Comments

@rabbitfr
Copy link

rabbitfr commented Nov 25, 2020

Hi,

I have some questions about regexTokens and not parsing some parts of an input.

See file at bottom for reference.

Ignore

In main() there is a line to parse :

 rule: StartBonus = GRAPH 1:entrance(x=2, y=3)

But StartBonus may have a constructor like in entrance, which may
be empty, like in

rule: StartBonus() = GRAPH 1:entrance(x=2, y=3)

Or it can have things inside, but I do not want to parse them. I want to ignore them.

rule: StartBonus(foo) = GRAPH 1:entrance(x=2, y=3)

But when I try to add a regexp like ([^)].*) it messes up with for example lpar matching.

regexTokens

I think it's related.

At start of input file there is :

version: 0.5f

0.5f regexp (not present in file) matches a lot of things.

So in the next line

alphabetFile: missionAlphabet.xpr

will be matched by the 0.5f regexp

Sample (can be run) code :

import com.github.h0tk3y.betterParse.combinators.*
import com.github.h0tk3y.betterParse.grammar.Grammar
import com.github.h0tk3y.betterParse.grammar.parseToEnd
import com.github.h0tk3y.betterParse.grammar.parser
import com.github.h0tk3y.betterParse.lexer.literalToken
import com.github.h0tk3y.betterParse.lexer.regexToken

interface Line

data class Version(val value: String) : Line
data class AlphabetFile(val file: String) : Line

sealed class Expression
data class TileMap(val width: Int, val height: Int) : Expression()
data class Graph(val symbols: List<Symbol>) : Expression()

sealed class Symbol
data class Node(val id: Int, val name: String, val constructor: Constructor) : Symbol()
//data class Edge(val id: String, val name: String, val source: String, val target: String) : Symbol

// Assignment or BooleanExpression
sealed class Argument
data class Assignment(val variable: String, val value: Any) : Argument()

data class Constructor(val arguments: List<Argument>)

data class Start(val expression: Expression) : Line
data class Rule(val name: String, val type: Expression) : Line

data class GGrammar(
        val version: Version,
        val alphabetFile: AlphabetFile,
        val start: Start,
        val rule: List<Rule>) {

    override fun toString(): String {
        return listOf(version, alphabetFile, start, rule.joinToString("\n")).joinToString("\n")
    }
}

object GrammarParser2 : Grammar<GGrammar>() {

    // literal first
    private val versionLiteral by literalToken("version: ")
    private val version by literalToken("0.5f") // bad
    private val alphabetFileLiteral by literalToken("alphabetFile: ")
    private val alphabet by literalToken("missionAlphabet.xpr") // bad
    private val startLiteral by literalToken("start: ")
    private val graphLiteral by literalToken("GRAPH")
    private val tileMapLiteral by literalToken("TILEMAP")
    private val rule by literalToken("rule: ")

    private val colon by literalToken(":")
    private val lpar by literalToken("(")
    private val rpar by literalToken(")")
    private val set by literalToken("=")
    private val coma by literalToken(", ")

    // main grammar parsers
    val versionParser by (versionLiteral and parser(this::version)) use { Version(t2.text) }
    val alphabetParser by (alphabetFileLiteral and parser(this::alphabet)) use { AlphabetFile(t2.text) }

    val tileMapParser by (tileMapLiteral and -parser(this::ws) and parser(this::integer) and -parser(this::ws) and parser(this::integer)) use { TileMap(t2.text.toInt(), t3.text.toInt()) }

    val assignmentParser by (parser(this::word) and -set and (parser(this::word) or parser(this::integer))) use { Assignment(t1.text, t2.text) }

    val constructorParser by (lpar and separatedTerms(assignmentParser, coma) and rpar) use { Constructor(t2) }

    val nodeParser by (parser(this::integer) and -colon and parser(this::word) and constructorParser) use { Node(t1.text.toInt(), t2.text, t3 ) }

    val graphParser by (graphLiteral and -parser(this::ws) and nodeParser) use { Graph(listOf(t2)) }

    val expressionParser = (tileMapParser or graphParser)

    val startParser by (startLiteral and expressionParser ) map { Start(it.t2) }
alphabetFile: missionAlphabet.xpr
    val ruleParser by separatedTerms((-rule and parser(this::word) and set and expressionParser) use { Rule(t1.text, t3) }, parser(this::NEWLINE))

    // regex last
    private val NEWLINE by regexToken("\n")

    private val integer by regexToken("\\d+")
    private val word by regexToken("\\w+")

    private val ws by regexToken("\\s+", ignore = true)

    override val rootParser by (
                    versionParser   * -NEWLINE *
                    alphabetParser  * -NEWLINE *
                    startParser     * -NEWLINE *
                    ruleParser
            ).map {
                GGrammar(it.t1, it.t2, it.t3, it.t4)
            }
}


fun main() {

    val text = """
            version: 0.5f
            alphabetFile: missionAlphabet.xpr
            start: GRAPH 0:Start(var=12, y=20)
            rule: StartBonus = GRAPH 1:entrance(x=2, y=3)
        """.trimIndent()

    println(GrammarParser2.parseToEnd(text))
}
@rabbitfr
Copy link
Author

Found out by myself for the constructor part, using optional and acceptZero = true

data class Function(val name: String, val arguments: List<Argument>)

data class Constructor(val arguments: List<Argument>)

object test : Grammar<Function>() {

    private val lpar by literalToken("(")

    private val rpar by literalToken(")")

    private val set by literalToken("=")

    private val coma by literalToken(", ")

    private val variable by regexToken("\\w+")

    private val string by regexToken("\"\\w+\"")

    private val integer by regexToken("\\d+")

    private val ws by regexToken("\\s+", ignore = true)

    val assignmentParser by (variable and set and ( variable or integer or string )) use { Assignment(t1.text,
            when (t3.type) {
                variable -> t3.text
                integer -> t3.text.toInt()
                string -> t3.text
                else -> throw IllegalStateException("unkown type ${t3.type}")
            })}

    val constructorParser by (lpar and separatedTerms(assignmentParser, coma, acceptZero = true) and rpar) use { Constructor(t2) }

    private val functionParser by (variable and optional(constructorParser)) use { Function(t1.text, t2?.arguments ?: emptyList())}

    override val rootParser by functionParser
}

fun main() {

    println(test.parseToEnd("hello"))
    println(test.parseToEnd("hello()"))
    println(test.parseToEnd("hello(x=1)"))
    println(test.parseToEnd("hello(x=pouet)"))
    println(test.parseToEnd("hello(x=\"pouet\", y=2)"))

}
Function(name=hello, arguments=[])
Function(name=hello, arguments=[])
Function(name=hello, arguments=[Assignment(variable=x, value=1)])
Function(name=hello, arguments=[Assignment(variable=x, value=pouet)])
Function(name=hello, arguments=[Assignment(variable=x, value="pouet"), Assignment(variable=y, value=2)])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant