mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Урок 5. Логические выражения, оператор if/else
This commit is contained in:
parent
c842dd0de3
commit
0feac2a331
@ -3,4 +3,9 @@ word2 = PI + word
|
|||||||
str = "a" * 5 + "ba" * 7 + "\n"
|
str = "a" * 5 + "ba" * 7 + "\n"
|
||||||
print str * "3" * 2
|
print str * "3" * 2
|
||||||
print "word = " + word + "\n"
|
print "word = " + word + "\n"
|
||||||
print "word2 = " + word2
|
print "word2 = " + word2 + "\n"
|
||||||
|
print "1" > "abc"
|
||||||
|
print "\n"
|
||||||
|
if (1 < 2) print "1 = 1"
|
||||||
|
else print "1 != 1"
|
||||||
|
print "\n"
|
||||||
|
@ -7,6 +7,10 @@ package com.annimon.ownlang.lib;
|
|||||||
public final class NumberValue implements Value {
|
public final class NumberValue implements Value {
|
||||||
|
|
||||||
private final double value;
|
private final double value;
|
||||||
|
|
||||||
|
public NumberValue(boolean value) {
|
||||||
|
this.value = value ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
public NumberValue(double value) {
|
public NumberValue(double value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
@ -9,12 +9,12 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public final class Lexer {
|
public final class Lexer {
|
||||||
|
|
||||||
private static final String OPERATOR_CHARS = "+-*/()=";
|
private static final String OPERATOR_CHARS = "+-*/()=<>";
|
||||||
private static final TokenType[] OPERATOR_TOKENS = {
|
private static final TokenType[] OPERATOR_TOKENS = {
|
||||||
TokenType.PLUS, TokenType.MINUS,
|
TokenType.PLUS, TokenType.MINUS,
|
||||||
TokenType.STAR, TokenType.SLASH,
|
TokenType.STAR, TokenType.SLASH,
|
||||||
TokenType.LPAREN, TokenType.RPAREN,
|
TokenType.LPAREN, TokenType.RPAREN,
|
||||||
TokenType.EQ
|
TokenType.EQ, TokenType.LT, TokenType.GT
|
||||||
};
|
};
|
||||||
|
|
||||||
private final String input;
|
private final String input;
|
||||||
@ -98,10 +98,13 @@ public final class Lexer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final String word = buffer.toString();
|
final String word = buffer.toString();
|
||||||
if (word.equals("print")) {
|
switch (word) {
|
||||||
addToken(TokenType.PRINT);
|
case "print": addToken(TokenType.PRINT); break;
|
||||||
} else {
|
case "if": addToken(TokenType.IF); break;
|
||||||
addToken(TokenType.WORD, word);
|
case "else": addToken(TokenType.ELSE); break;
|
||||||
|
default:
|
||||||
|
addToken(TokenType.WORD, word);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,10 @@ package com.annimon.ownlang.parser;
|
|||||||
import com.annimon.ownlang.parser.ast.PrintStatement;
|
import com.annimon.ownlang.parser.ast.PrintStatement;
|
||||||
import com.annimon.ownlang.parser.ast.AssignmentStatement;
|
import com.annimon.ownlang.parser.ast.AssignmentStatement;
|
||||||
import com.annimon.ownlang.parser.ast.BinaryExpression;
|
import com.annimon.ownlang.parser.ast.BinaryExpression;
|
||||||
|
import com.annimon.ownlang.parser.ast.ConditionalExpression;
|
||||||
import com.annimon.ownlang.parser.ast.VariabletExpression;
|
import com.annimon.ownlang.parser.ast.VariabletExpression;
|
||||||
import com.annimon.ownlang.parser.ast.Expression;
|
import com.annimon.ownlang.parser.ast.Expression;
|
||||||
|
import com.annimon.ownlang.parser.ast.IfStatement;
|
||||||
import com.annimon.ownlang.parser.ast.ValueExpression;
|
import com.annimon.ownlang.parser.ast.ValueExpression;
|
||||||
import com.annimon.ownlang.parser.ast.Statement;
|
import com.annimon.ownlang.parser.ast.Statement;
|
||||||
import com.annimon.ownlang.parser.ast.UnaryExpression;
|
import com.annimon.ownlang.parser.ast.UnaryExpression;
|
||||||
@ -41,6 +43,9 @@ public final class Parser {
|
|||||||
if (match(TokenType.PRINT)) {
|
if (match(TokenType.PRINT)) {
|
||||||
return new PrintStatement(expression());
|
return new PrintStatement(expression());
|
||||||
}
|
}
|
||||||
|
if (match(TokenType.IF)) {
|
||||||
|
return ifElse();
|
||||||
|
}
|
||||||
return assignmentStatement();
|
return assignmentStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,10 +60,43 @@ public final class Parser {
|
|||||||
throw new RuntimeException("Unknown statement");
|
throw new RuntimeException("Unknown statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Statement ifElse() {
|
||||||
|
final Expression condition = expression();
|
||||||
|
final Statement ifStatement = statement();
|
||||||
|
final Statement elseStatement;
|
||||||
|
if (match(TokenType.ELSE)) {
|
||||||
|
elseStatement = statement();
|
||||||
|
} else {
|
||||||
|
elseStatement = null;
|
||||||
|
}
|
||||||
|
return new IfStatement(condition, ifStatement, elseStatement);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private Expression expression() {
|
private Expression expression() {
|
||||||
return additive();
|
return conditional();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Expression conditional() {
|
||||||
|
Expression result = additive();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (match(TokenType.EQ)) {
|
||||||
|
result = new ConditionalExpression('=', result, additive());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (match(TokenType.LT)) {
|
||||||
|
result = new ConditionalExpression('<', result, additive());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (match(TokenType.GT)) {
|
||||||
|
result = new ConditionalExpression('>', result, additive());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Expression additive() {
|
private Expression additive() {
|
||||||
|
@ -13,12 +13,16 @@ public enum TokenType {
|
|||||||
|
|
||||||
// keyword
|
// keyword
|
||||||
PRINT,
|
PRINT,
|
||||||
|
IF,
|
||||||
|
ELSE,
|
||||||
|
|
||||||
PLUS,
|
PLUS,
|
||||||
MINUS,
|
MINUS,
|
||||||
STAR,
|
STAR,
|
||||||
SLASH,
|
SLASH,
|
||||||
EQ,
|
EQ,
|
||||||
|
LT,
|
||||||
|
GT,
|
||||||
|
|
||||||
LPAREN, // (
|
LPAREN, // (
|
||||||
RPAREN, // )
|
RPAREN, // )
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
package com.annimon.ownlang.parser.ast;
|
||||||
|
|
||||||
|
import com.annimon.ownlang.lib.NumberValue;
|
||||||
|
import com.annimon.ownlang.lib.StringValue;
|
||||||
|
import com.annimon.ownlang.lib.Value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class ConditionalExpression implements Expression {
|
||||||
|
|
||||||
|
private final Expression expr1, expr2;
|
||||||
|
private final char operation;
|
||||||
|
|
||||||
|
public ConditionalExpression(char operation, Expression expr1, Expression expr2) {
|
||||||
|
this.operation = operation;
|
||||||
|
this.expr1 = expr1;
|
||||||
|
this.expr2 = expr2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value eval() {
|
||||||
|
final Value value1 = expr1.eval();
|
||||||
|
final Value value2 = expr2.eval();
|
||||||
|
if (value1 instanceof StringValue) {
|
||||||
|
final String string1 = value1.asString();
|
||||||
|
final String string2 = value2.asString();
|
||||||
|
switch (operation) {
|
||||||
|
case '<': return new NumberValue(string1.compareTo(string2) < 0);
|
||||||
|
case '>': return new NumberValue(string1.compareTo(string2) > 0);
|
||||||
|
case '=':
|
||||||
|
default:
|
||||||
|
return new NumberValue(string1.equals(string2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final double number1 = value1.asNumber();
|
||||||
|
final double number2 = value2.asNumber();
|
||||||
|
switch (operation) {
|
||||||
|
case '<': return new NumberValue(number1 < number2);
|
||||||
|
case '>': return new NumberValue(number1 > number2);
|
||||||
|
case '=':
|
||||||
|
default:
|
||||||
|
return new NumberValue(number1 == number2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("[%s %c %s]", expr1, operation, expr2);
|
||||||
|
}
|
||||||
|
}
|
37
src/com/annimon/ownlang/parser/ast/IfStatement.java
Normal file
37
src/com/annimon/ownlang/parser/ast/IfStatement.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package com.annimon.ownlang.parser.ast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author aNNiMON
|
||||||
|
*/
|
||||||
|
public final class IfStatement implements Statement {
|
||||||
|
|
||||||
|
private final Expression expression;
|
||||||
|
private final Statement ifStatement, elseStatement;
|
||||||
|
|
||||||
|
public IfStatement(Expression expression, Statement ifStatement, Statement elseStatement) {
|
||||||
|
this.expression = expression;
|
||||||
|
this.ifStatement = ifStatement;
|
||||||
|
this.elseStatement = elseStatement;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
final double result = expression.eval().asNumber();
|
||||||
|
if (result != 0) {
|
||||||
|
ifStatement.execute();
|
||||||
|
} else if (elseStatement != null) {
|
||||||
|
elseStatement.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder result = new StringBuilder();
|
||||||
|
result.append("if ").append(expression).append(' ').append(ifStatement);
|
||||||
|
if (elseStatement != null) {
|
||||||
|
result.append("\nelse ").append(elseStatement);
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user