11package eu.yeger.cyk.parser
22
3- import eu.yeger.cyk.*
4- import eu.yeger.cyk.model.*
5-
6- private const val terminalSymbolRegexString = " [a-z]+"
7- private const val nonTerminalSymbolRegexString = " [A-Z]+[a-z]*"
8-
9- public val terminalSymbolRegex: Regex = terminalSymbolRegexString.toRegex()
10- public val nonTerminalSymbolRegex: Regex = nonTerminalSymbolRegexString.toRegex()
11- public val productionRuleRegex: Regex = " $nonTerminalSymbolRegexString -> ($nonTerminalSymbolRegexString $nonTerminalSymbolRegexString |$terminalSymbolRegexString )" .toRegex()
3+ import eu.yeger.cyk.Result
4+ import eu.yeger.cyk.map
5+ import eu.yeger.cyk.model.Grammar
6+ import eu.yeger.cyk.model.StartSymbol
127
138public fun grammar (
149 startSymbol : String ,
1510 includeEmptyProductionRule : Boolean = false,
1611 block : () -> String ,
1712): Result <Grammar > {
18- return parseAsGrammar (
13+ return grammar (
1914 startSymbol = startSymbol,
2015 includeEmptyProductionRule = includeEmptyProductionRule,
2116 productionRules = block(),
2217 )
2318}
2419
25- public fun parseAsGrammar (
20+ public fun grammar (
2621 startSymbol : String ,
2722 includeEmptyProductionRule : Boolean = false,
2823 productionRules : String ,
2924): Result <Grammar > {
30- return parse (
25+ return parseProductionRules (
3126 startSymbol = startSymbol,
3227 includeEmptyProductionRule = includeEmptyProductionRule,
3328 productionRules = productionRules
@@ -38,76 +33,3 @@ public fun parseAsGrammar(
3833 )
3934 }
4035}
41-
42- public fun parse (
43- startSymbol : String ,
44- includeEmptyProductionRule : Boolean = false,
45- productionRules : String ,
46- ): Result <ProductionRuleSet > {
47- return validateStartSymbol(startSymbol)
48- .andThen { validatedStartSymbol ->
49- productionRules.trimIndent()
50- .lines()
51- .filter { it.isNotBlank() }
52- .parseLines(validatedStartSymbol)
53- }
54- .map { productionRuleSet ->
55- when (includeEmptyProductionRule) {
56- true -> productionRuleSet.copy(terminatingRules = productionRuleSet.terminatingRules + TerminatingRule (StartSymbol (startSymbol), TerminalSymbol (" " )))
57- else -> productionRuleSet
58- }
59- }
60- }
61-
62- private fun validateStartSymbol (startSymbol : String ): Result <StartSymbol > {
63- return when {
64- startSymbol matches nonTerminalSymbolRegex -> succeed(StartSymbol (startSymbol))
65- startSymbol.isBlank() -> fail(" Start symbol cannot be blank." )
66- else -> fail(" Invalid start symbol: $startSymbol " )
67- }
68- }
69-
70- private fun List<String>.parseLines (startSymbol : StartSymbol ): Result <ProductionRuleSet > {
71- return fold(succeed(emptyList())) { productionRules: Result <List <ProductionRule >>, line: String ->
72- productionRules
73- .and (line.parseLine(startSymbol))
74- .andThen { productionRule: ProductionRule -> succeed(productionRules.getOr(emptyList()) + productionRule) }
75- }.map { productionRules -> productionRuleSet(productionRules) }
76- }
77-
78- private fun String.parseLine (startSymbol : StartSymbol ): Result <ProductionRule > {
79- return trim()
80- .splitIntoComponents()
81- .andThen { components -> components.asProductionRule(startSymbol) }
82- }
83-
84- private fun String.splitIntoComponents (): Result <List <String >> {
85- return when {
86- this matches productionRuleRegex -> succeed(split(" ->" , " " ).filter { it.isNotBlank() })
87- else -> fail(" Invalid production rule: $this " )
88- }
89- }
90-
91- private fun List<String>.asProductionRule (startSymbol : StartSymbol ): Result <ProductionRule > {
92- val inputSymbol = when (val inputString = get(0 )) {
93- startSymbol.symbol -> startSymbol
94- else -> RegularNonTerminalSymbol (inputString)
95- }
96- return when (size) {
97- 3 -> asNonTerminatingProductionRule(inputSymbol)
98- 2 -> asTerminatingProductionRule(inputSymbol)
99- else -> fail(" Invalid component amount ($size )! Must be 2 for terminal or 3 for non terminal production rules." )
100- }
101- }
102-
103- private fun List<String>.asNonTerminatingProductionRule (inputSymbol : NonTerminalSymbol ): Result <NonTerminatingRule > {
104- return succeed(NonTerminatingRule (inputSymbol, RegularNonTerminalSymbol (get(1 )) to RegularNonTerminalSymbol (get(2 ))))
105- }
106-
107- private fun List<String>.asTerminatingProductionRule (inputSymbol : NonTerminalSymbol ): Result <TerminatingRule > {
108- val outputSymbol = when (val terminalSymbol = get(1 )) {
109- epsilon -> TerminalSymbol (terminalSymbol)
110- else -> TerminalSymbol (terminalSymbol)
111- }
112- return succeed(TerminatingRule (inputSymbol, outputSymbol))
113- }
0 commit comments