Guest User

Shunting-Yard

a guest
Mar 7th, 2016
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5.11 KB | None | 0 0
  1. // Токены: числа, операторы и прочие символы
  2. public class Token {
  3.     enum Type {
  4.         ERROR,
  5.         NUMBER,
  6.         OPERATOR,
  7.         BRACE,
  8.         EOF
  9.     }
  10.    
  11.     private Type type;
  12.     private String text;
  13.     private int pos;
  14.  
  15.     public Type getType() {
  16.         return type;
  17.     }
  18.  
  19.     public String getText() {
  20.         return text;
  21.     }
  22.    
  23.     public Token(Type type, String text, int pos) {
  24.         this.type = type;
  25.         this.text = text;
  26.         this.pos = pos;
  27.     }
  28.  
  29.     @Override
  30.     public String toString() {
  31.         return text;
  32.     }
  33. }
  34.  
  35. // Сканер: разбивает входную строку на последовательность токенов
  36. public class Scanner {
  37.     private String in;
  38.     private int pos;
  39.    
  40.     private StringBuilder bld;
  41.    
  42.     public Scanner(String in) {
  43.         this.in = in;
  44.         pos = 0;
  45.     }
  46.    
  47.     public Token tokenize() {
  48.         bld = new StringBuilder();            
  49.         int start = pos;
  50.         for (pos = pos; pos < in.length(); pos++) {
  51.             char ch = lookup(pos);            
  52.             start = pos;
  53.             if (Character.isDigit(ch)) {
  54.                 return new Token(Token.Type.NUMBER, readNumber(), start);
  55.             } else if (isOperator(ch)) {
  56.                 pos++;
  57.                 return new Token(Token.Type.OPERATOR, Character.toString(ch), start);
  58.             } else if (isBrace(ch)) {
  59.                 pos++;
  60.                 return new Token(Token.Type.BRACE, Character.toString(ch), start);
  61.             } else if (Character.isWhitespace(ch)) {
  62.                 continue;
  63.             } else {
  64.                 return new Token(Token.Type.ERROR, \\_(ツ)_/¯", start);
  65.             }
  66.         }
  67.         return new Token(Token.Type.EOF, "", pos);
  68.     }
  69.    
  70.     private boolean isBrace(char ch) {
  71.         return ch == '(' || ch == ')';
  72.     }
  73.    
  74.     private boolean isOperator(char ch) {
  75.         switch (ch) {
  76.             case '+':
  77.             case '-':
  78.             case '*':
  79.             case '/':
  80.                 return true;
  81.             default:
  82.                 return false;
  83.         }
  84.     }
  85.    
  86.     private String readNumber() {
  87.         for (char ch = lookup(pos); Character.isDigit(ch); ch = lookup(++pos)) {
  88.             bld.append(ch);
  89.         }
  90.         return bld.toString();
  91.     }
  92.    
  93.     private char lookup(int pos) {
  94.         if (pos >= in.length()) {
  95.             return '\0';
  96.         } else {
  97.             return in.charAt(pos);
  98.         }
  99.     }
  100. }
  101.  
  102. // Сама «сортировочная станция»
  103. public class ShuntingYard {
  104.     private Scanner scanner;
  105.     private ArrayList<Token> out;
  106.     private Stack<Token> stack;
  107.     private final static HashMap<String, Short> precedence;
  108.    
  109.     static {
  110.         precedence = new HashMap<>();
  111.         precedence.put("+", (short) 4);
  112.         precedence.put("-", (short) 4);
  113.         precedence.put("*", (short) 5);
  114.         precedence.put("/", (short) 5);
  115.     }
  116.    
  117.     public ShuntingYard(Scanner scanner) {
  118.         this.scanner = scanner;
  119.     }
  120.    
  121.     private int precedence(String op) {
  122.         return precedence.get(op);
  123.     }
  124.    
  125.     public ArrayList<Token> convert() {
  126.         out = new ArrayList<Token>();
  127.         stack = new Stack<Token>();
  128.        
  129.         loop:
  130.         for (Token t = scanner.tokenize(); t.getType() != Token.Type.EOF; t = scanner.tokenize()) {
  131.             switch (t.getType()) {
  132.                 case NUMBER:
  133.                     out.add(t);
  134.                     break;
  135.                 case OPERATOR:
  136.                     while (!stack.empty() && stack.peek().getType() == Token.Type.OPERATOR) {
  137.                         if (precedence(t.getText()) <= precedence(stack.peek().getText())) {
  138.                             out.add(stack.pop());
  139.                         } else {
  140.                             break;
  141.                         }
  142.                     }
  143.                     stack.add(t);
  144.                     break;
  145.                 case BRACE:
  146.                     if (t.getText().equals("(")) {
  147.                         stack.push(t);
  148.                     } else {
  149.                         if (stack.empty()) {
  150.                             throw new Error("Unbalanced parentheses");
  151.                         }
  152.                        
  153.                         while (!stack.peek().getText().equals("(")) {
  154.                             out.add(stack.pop());
  155.                            
  156.                             if (stack.empty()) {
  157.                                 throw new Error("Unbalanced parentheses");
  158.                             }
  159.                         }
  160.                         stack.pop();
  161.                     }
  162.                     break;
  163.                 default:
  164.                     throw new Error("Unknown token `" + t + "`");
  165.             }
  166.         }
  167.        
  168.         while (!stack.empty()) {
  169.             out.add(stack.pop());
  170.         }
  171.         return out;
  172.     }
  173. }
  174.  
  175. // Использование:
  176. ShuntingYard yard = new ShuntingYard(new Scanner("(5 + 21) * 2"));
  177. ArrayList<Token> out = yard.convert();
Advertisement
Add Comment
Please, Sign In to add comment