Skip to content

Commit a200303

Browse files
committed
parse to ast, except functions
1 parent de9d1cd commit a200303

File tree

5 files changed

+834
-0
lines changed

5 files changed

+834
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.github.murzagalin.evaluator.ast
2+
3+
import com.github.murzagalin.evaluator.Token
4+
5+
sealed class Expression {
6+
data class Unary(
7+
val token: Token.Operator,
8+
val expression: Expression
9+
) : Expression()
10+
11+
data class Binary(
12+
val token: Token.Operator,
13+
val leftExpression: Expression,
14+
val rightExpression: Expression
15+
) : Expression()
16+
17+
data class Ternary(
18+
val token: Token.Operator,
19+
val firstExpression: Expression,
20+
val secondExpression: Expression,
21+
val thirdExpression: Expression
22+
) : Expression()
23+
24+
data class Terminal(
25+
val token: Token.Operand
26+
) : Expression()
27+
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package com.github.murzagalin.evaluator.ast
2+
3+
import com.github.murzagalin.evaluator.Token
4+
5+
6+
/* the parser uses these rules
7+
8+
* expression -> ternary_if
9+
* ternary_if -> logic_or ( "?" ternary_if ":" ternary_if )?
10+
* logic_or -> logic_and ( ( "or" | "||" ) logic_and )*
11+
* logic_and -> equality ( ( "and" | "&&" ) equality )*
12+
* equality -> comparison ( ( "!=" | "==" ) comparison )*
13+
* comparison -> term ( ( ">" | ">=" | "<" | "<=" ) term )*
14+
* term -> factor ( ( "-" | "+" ) factor )*
15+
* factor -> unary ( ( "/" | "*" | "%") unary )*
16+
* unary -> ( "!" | "-" | "+" ) unary | exponent
17+
* exponent -> identifier ( "^" unary )*
18+
- identifier -> function | variable | number | boolean
19+
20+
function -> name "(" ( arguments )* ")"
21+
arguments -> expression ( ',' expression )*
22+
* variable -> name
23+
* name -> CHAR ( CHAR | DIGIT )*
24+
* boolean -> "true" | "false" | "TRUE" | "FALSE"
25+
* number -> DIGIT ( DIGIT )*
26+
*/
27+
28+
class Parser {
29+
30+
private val equalityTokens = setOf(Token.Operator.Equal, Token.Operator.NotEqual)
31+
32+
private val comparisonTokens = setOf(
33+
Token.Operator.GreaterThan,
34+
Token.Operator.GreaterEqualThan,
35+
Token.Operator.LessThan,
36+
Token.Operator.LessEqualThan
37+
)
38+
39+
private val termTokens = setOf(Token.Operator.Plus, Token.Operator.Minus)
40+
41+
private val factorTokens = setOf(Token.Operator.Division, Token.Operator.Multiplication, Token.Operator.Modulo)
42+
43+
private val unaryTokens = setOf(Token.Operator.UnaryPlus, Token.Operator.UnaryMinus, Token.Operator.Not)
44+
45+
private var ix = 0
46+
47+
fun parse(tokens: List<Token>): Expression {
48+
ix = 0
49+
return expression(tokens)
50+
}
51+
52+
fun expression(tokens: List<Token>): Expression {
53+
return ternaryIf(tokens)
54+
}
55+
56+
private fun ternaryIf(tokens: List<Token>): Expression {
57+
val first = logicOr(tokens)
58+
59+
if (ix < tokens.size && tokens[ix] is Token.Operator.TernaryIf) {
60+
ix++
61+
val second = ternaryIf(tokens)
62+
require(tokens[ix++] is Token.Operator.TernaryElse) { "':' expected in ternary-if-else expression" }
63+
val third = ternaryIf(tokens)
64+
65+
return Expression.Ternary(Token.Operator.TernaryIfElse, first, second, third)
66+
}
67+
68+
return first
69+
}
70+
71+
private fun logicOr(tokens: List<Token>): Expression {
72+
var left = logicAnd(tokens)
73+
74+
while (ix < tokens.size && tokens[ix] is Token.Operator.Or) {
75+
ix++
76+
val right = logicAnd(tokens)
77+
left = Expression.Binary(Token.Operator.Or, left, right)
78+
}
79+
80+
return left
81+
}
82+
83+
private fun logicAnd(tokens: List<Token>): Expression {
84+
var left = equality(tokens)
85+
86+
while (ix < tokens.size && tokens[ix] is Token.Operator.And) {
87+
ix++
88+
val right = equality(tokens)
89+
left = Expression.Binary(Token.Operator.And, left, right)
90+
}
91+
92+
return left
93+
}
94+
95+
private fun equality(tokens: List<Token>): Expression {
96+
var left = comparison(tokens)
97+
98+
while (ix < tokens.size && tokens[ix] in equalityTokens) {
99+
val operator = tokens[ix++]
100+
val right = comparison(tokens)
101+
left = Expression.Binary(operator as Token.Operator, left, right)
102+
}
103+
104+
return left
105+
}
106+
107+
private fun comparison(tokens: List<Token>): Expression {
108+
var left = term(tokens)
109+
110+
while (ix < tokens.size && tokens[ix] in comparisonTokens) {
111+
val operator = tokens[ix++]
112+
val right = term(tokens)
113+
left = Expression.Binary(operator as Token.Operator, left, right)
114+
}
115+
116+
return left
117+
}
118+
119+
private fun term(tokens: List<Token>): Expression {
120+
var left = factor(tokens)
121+
122+
while (ix < tokens.size && tokens[ix] in termTokens) {
123+
val operator = tokens[ix++]
124+
val right = factor(tokens)
125+
left = Expression.Binary(operator as Token.Operator, left, right)
126+
}
127+
128+
return left
129+
}
130+
131+
private fun factor(tokens: List<Token>): Expression {
132+
var left = unary(tokens)
133+
134+
while (ix < tokens.size && tokens[ix] in factorTokens) {
135+
val operator = tokens[ix++]
136+
val right = unary(tokens)
137+
left = Expression.Binary(operator as Token.Operator, left, right)
138+
}
139+
140+
return left
141+
}
142+
143+
private fun unary(tokens: List<Token>): Expression {
144+
return if (ix < tokens.size && tokens[ix] in unaryTokens) {
145+
val unaryToken = tokens[ix++]
146+
147+
Expression.Unary(unaryToken as Token.Operator, unary(tokens))
148+
} else {
149+
exponent(tokens)
150+
}
151+
}
152+
153+
private fun exponent(tokens: List<Token>): Expression {
154+
var identifier = identifier(tokens)
155+
156+
if (ix < tokens.size && tokens[ix] is Token.Operator.Power) {
157+
ix++
158+
identifier = Expression.Binary(Token.Operator.Power, identifier, unary(tokens))
159+
}
160+
161+
return identifier
162+
}
163+
164+
private fun identifier(tokens: List<Token>): Expression {
165+
require(tokens.size > ix) { "Expression expected" }
166+
167+
return when (val token = tokens[ix++]) {
168+
is Token.Operand -> Expression.Terminal(token)
169+
is Token.Bracket.Left -> {
170+
val result = expression(tokens)
171+
require(tokens[ix++] is Token.Bracket.Right) { "')' expected after expression" }
172+
result
173+
}
174+
else -> throw IllegalArgumentException("Expression expected")
175+
}
176+
}
177+
}

0 commit comments

Comments
 (0)