Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Токены: числа, операторы и прочие символы
- public class Token {
- enum Type {
- ERROR,
- NUMBER,
- OPERATOR,
- BRACE,
- EOF
- }
- private Type type;
- private String text;
- private int pos;
- public Type getType() {
- return type;
- }
- public String getText() {
- return text;
- }
- public Token(Type type, String text, int pos) {
- this.type = type;
- this.text = text;
- this.pos = pos;
- }
- @Override
- public String toString() {
- return text;
- }
- }
- // Сканер: разбивает входную строку на последовательность токенов
- public class Scanner {
- private String in;
- private int pos;
- private StringBuilder bld;
- public Scanner(String in) {
- this.in = in;
- pos = 0;
- }
- public Token tokenize() {
- bld = new StringBuilder();
- int start = pos;
- for (pos = pos; pos < in.length(); pos++) {
- char ch = lookup(pos);
- start = pos;
- if (Character.isDigit(ch)) {
- return new Token(Token.Type.NUMBER, readNumber(), start);
- } else if (isOperator(ch)) {
- pos++;
- return new Token(Token.Type.OPERATOR, Character.toString(ch), start);
- } else if (isBrace(ch)) {
- pos++;
- return new Token(Token.Type.BRACE, Character.toString(ch), start);
- } else if (Character.isWhitespace(ch)) {
- continue;
- } else {
- return new Token(Token.Type.ERROR, "¯\\_(ツ)_/¯", start);
- }
- }
- return new Token(Token.Type.EOF, "", pos);
- }
- private boolean isBrace(char ch) {
- return ch == '(' || ch == ')';
- }
- private boolean isOperator(char ch) {
- switch (ch) {
- case '+':
- case '-':
- case '*':
- case '/':
- return true;
- default:
- return false;
- }
- }
- private String readNumber() {
- for (char ch = lookup(pos); Character.isDigit(ch); ch = lookup(++pos)) {
- bld.append(ch);
- }
- return bld.toString();
- }
- private char lookup(int pos) {
- if (pos >= in.length()) {
- return '\0';
- } else {
- return in.charAt(pos);
- }
- }
- }
- // Сама «сортировочная станция»
- public class ShuntingYard {
- private Scanner scanner;
- private ArrayList<Token> out;
- private Stack<Token> stack;
- private final static HashMap<String, Short> precedence;
- static {
- precedence = new HashMap<>();
- precedence.put("+", (short) 4);
- precedence.put("-", (short) 4);
- precedence.put("*", (short) 5);
- precedence.put("/", (short) 5);
- }
- public ShuntingYard(Scanner scanner) {
- this.scanner = scanner;
- }
- private int precedence(String op) {
- return precedence.get(op);
- }
- public ArrayList<Token> convert() {
- out = new ArrayList<Token>();
- stack = new Stack<Token>();
- loop:
- for (Token t = scanner.tokenize(); t.getType() != Token.Type.EOF; t = scanner.tokenize()) {
- switch (t.getType()) {
- case NUMBER:
- out.add(t);
- break;
- case OPERATOR:
- while (!stack.empty() && stack.peek().getType() == Token.Type.OPERATOR) {
- if (precedence(t.getText()) <= precedence(stack.peek().getText())) {
- out.add(stack.pop());
- } else {
- break;
- }
- }
- stack.add(t);
- break;
- case BRACE:
- if (t.getText().equals("(")) {
- stack.push(t);
- } else {
- if (stack.empty()) {
- throw new Error("Unbalanced parentheses");
- }
- while (!stack.peek().getText().equals("(")) {
- out.add(stack.pop());
- if (stack.empty()) {
- throw new Error("Unbalanced parentheses");
- }
- }
- stack.pop();
- }
- break;
- default:
- throw new Error("Unknown token `" + t + "`");
- }
- }
- while (!stack.empty()) {
- out.add(stack.pop());
- }
- return out;
- }
- }
- // Использование:
- ShuntingYard yard = new ShuntingYard(new Scanner("(5 + 21) * 2"));
- ArrayList<Token> out = yard.convert();
Advertisement
Add Comment
Please, Sign In to add comment