1. package com.smotricz.morgana6.client.parser;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. import com.smotricz.morgana6.client.nodes.AndNode;
  7. import com.smotricz.morgana6.client.nodes.ConstNode;
  8. import com.smotricz.morgana6.client.nodes.Node;
  9. import com.smotricz.morgana6.client.nodes.OrNode;
  10. import com.smotricz.morgana6.client.nodes.ParenNode;
  11. import com.smotricz.morgana6.client.nodes.SignedNode;
  12. import com.smotricz.morgana6.client.nodes.VarNode;
  13.  
  14. import static com.smotricz.morgana6.client.parser.Token.*;
  15.  
  16. public class Parser {
  17.  
  18.     private List<Token> tokens;
  19.     private int ptr;
  20.    
  21.    
  22.     /**
  23.      * Constructor.
  24.      */
  25.     public Parser() {
  26.         this.tokens = new ArrayList<Token>();
  27.     }
  28.  
  29.    
  30.     public Node parse(String input, StringBuilder cleaned) throws ParseException {
  31.         String clean = Scanner.scan(input, this.tokens);
  32.         if (cleaned != null) {
  33.             cleaned.setLength(0);
  34.             cleaned.append(clean);
  35.         }
  36.         setPtr(0);
  37.         Node exp = orExp();
  38.         if (exp == null) {
  39.             throw new ParseException("Syntax error", 0);
  40.         }
  41.         if (la(0) != EOD) {
  42.             throw new ParseException("Syntax error", this.ptr);
  43.         }
  44.         return exp;
  45.     }
  46.  
  47.  
  48.     /**
  49.      * Look Ahead.  
  50.      * @param offset
  51.      * @return the token type of the input token at {@link #ptr} + offset.
  52.      */
  53.     private TT la(int offset) {
  54.         return tokens.get(ptr + offset).type;
  55.     }
  56.    
  57.    
  58.     private Token nextToken() {
  59.         return tokens.get(ptr);
  60.     }
  61.    
  62.    
  63.     private void setPtr(int position) {
  64.         this.ptr = position;
  65.     }
  66.    
  67.    
  68.     private int getPtr() {
  69.         return this.ptr;
  70.     }
  71.    
  72.    
  73.     private void consume() {
  74.         this.ptr++;
  75.     }
  76.    
  77.    
  78.     // and-exp (OR and-exp)*
  79.     private Node orExp() {
  80.         Node a1 = andExp();
  81.         if (a1 == null) return null;
  82.         if (la(0) != OR) return a1;
  83.         consume();
  84.         Node a2 = andExp();
  85.         if (a2 == null) return a1;
  86.         ArrayList<Node> terms = new ArrayList<Node>();
  87.         terms.add(a1);
  88.         terms.add(a2);
  89.         while (la(0) == OR) {
  90.             consume();
  91.             Node aN = andExp();
  92.             if (aN == null) break;
  93.             terms.add(aN);
  94.         }
  95.         return new OrNode(terms);
  96.     }
  97.    
  98.  
  99.     // signed-exp ([AND] signed-exp)*
  100.     private Node andExp() {
  101.         Node s1 = signed();
  102.         if (s1 == null) return null;
  103.         if (la(0) == AND) {
  104.             consume();
  105.         }
  106.         Node s2 = signed();
  107.         if (s2 == null) return s1;
  108.         ArrayList<Node> terms = new ArrayList<Node>();
  109.         terms.add(s1);
  110.         terms.add(s2);
  111.         while (true) {
  112.             if (la(0) == AND) {
  113.                 consume();
  114.             }
  115.             Node sN = signed();
  116.             if (sN == null) break;
  117.             terms.add(sN);
  118.         }
  119.         return new AndNode(terms);
  120.     }
  121.    
  122.    
  123.     // NOT scalar
  124.     // | scalar [PRIME]
  125.     private Node signed() {
  126.         boolean negative = (la(0) == NOT);
  127.         if (negative) {
  128.             consume();
  129.         }
  130.         Node scx = scalar();
  131.         if (scx == null) return null;
  132.         if (negative) return ((SignedNode) scx).negate();
  133.         if (la(0) == PRIME) {
  134.             consume();
  135.             return ((SignedNode) scx).negate();
  136.         } else {
  137.             return scx;
  138.         }
  139.     }
  140.    
  141.    
  142.     // VAR
  143.     // | CONSTANT
  144.     // | LP or-exp RP
  145.     private Node scalar() {
  146.         int savPtr = getPtr();
  147.         Node scx;
  148.         if (la(0) == VAR) {
  149.             scx = VarNode.forName(String.valueOf(nextToken().text));
  150.             consume();
  151.             return scx;
  152.         }
  153.         if (la(0) == CONST) {
  154.             scx = ConstNode.forBoolean(nextToken().text == '1');
  155.             consume();
  156.             return scx;
  157.         }
  158.         if (la(0) == LP) {
  159.             consume();
  160.             scx = orExp();
  161.             if (scx == null || la(0) != RP) {
  162.                 setPtr(savPtr);
  163.                 return null;
  164.             }
  165.             consume();
  166.             return ParenNode.forNested(scx);
  167.         }
  168.         return null;
  169.     }
  170.    
  171. }