All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jclarion.clarion.runtime.expr.Parser Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2010, by Andrew Barnham
 *
 * The contents of this file are subject to
 * GNU Lesser General Public License (LGPL), v.3
 * http://www.gnu.org/licenses/lgpl.txt
 * 
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 */
package org.jclarion.clarion.runtime.expr;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jclarion.clarion.ClarionDecimal;
import org.jclarion.clarion.ClarionNumber;
import org.jclarion.clarion.ClarionString;
import org.jclarion.clarion.lang.*;

public class Parser {

    private Lexer stream;

    public Parser(Lexer stream)
    {
        this.stream=stream;
    }
    
    public CExpr expr() throws ParseException
    {
        CExpr result = expr1();
        enforceNext(LexType.eof,"Expected EOF");
        return result;
    }
    
    private CExpr expr1() throws ParseException
    {
        CExpr result = expr2();
        if (result==null) return null;
        
        while ( true ) {
            Lex la = stream.lookahead();
            if (la.type==LexType.label && 
                (la.value.equalsIgnoreCase("and") ||
                 la.value.equalsIgnoreCase("or")))
            {
                stream.begin();
                stream.next();
                CExpr right = expr2();
                if (right!=null) {
                    result=BoolExpr.construct(result,la.value,right);
                    stream.commit();
                    continue;
                } else {
                    stream.rollback();
                }
            }
            break;
        }
        return result;
    }
    
    private CExpr expr2()  throws ParseException {
        
        Lex la = stream.lookahead();
        
        if ((la.type==LexType.comparator && la.value.equals("~")) ||
            (la.type==LexType.label && la.value.equalsIgnoreCase("not"))) 
        {
            stream.begin();
            stream.next();
            CExpr result = expr3();
            if (result!=null) {
                result=new NotExpr(result);
                stream.commit();
            } else {
                stream.rollback();
            }
            return result;
        }
        
        return expr3();
    }

    private static Map opMap=new HashMap();
    private static Map negMap=new HashMap();
    static {
        opMap.put("<>","<>");
        opMap.put("~=","<>");
        opMap.put("=>",">=");
        opMap.put(">=",">=");
        opMap.put("=<","<=");
        opMap.put("<=","<=");
        opMap.put("<","<");
        opMap.put(">",">");
        opMap.put("=","=");
        opMap.put("&=","&=");

        negMap.put("<>","=");
        negMap.put("=","<>");
        negMap.put("<",">=");
        negMap.put("<=",">");
        negMap.put(">","<=");
        negMap.put(">=","<");
    };
    
    private CExpr expr3()  throws ParseException {
        CExpr result = expr4();
        if (result==null) return null;
        
        while ( true ) {
            
            stream.begin();
            boolean not=false;
            
            Lex la = stream.lookahead();
            if ((la.type==LexType.comparator && la.value.equals("~")) ||
                    (la.type==LexType.label && la.value.equalsIgnoreCase("not"))) 
            {
                stream.next();
                not=true;
                la = stream.lookahead();
            }
        
            String op=null;
            if (la.type!=LexType.string) {
                op=opMap.get(la.value);
            }

            if (op!=null && not) {
                op=negMap.get(op);
            }
            
            if (op==null) {
                stream.rollback();
                break;
            }
            
            stream.next();
            CExpr right = expr4();
            if (right==null) {
                stream.rollback();
                break;
            }
            stream.commit();
            result=new CmpExpr(result,op,right);
        }
        
        return result;
    }

    private CExpr expr4()  throws ParseException {
        CExpr result = expr5();
        if (result==null) return null;
        
        while ( true ) {
            if (stream.lookahead().type!=LexType.reference) break;
            stream.begin();
            stream.next();
            CExpr right=expr5();
            if (right!=null) {
                stream.commit();
                result=ConcatExpr.construct(result,right);
                continue;
            }
            stream.rollback();
            break;
        }
        return result;
    }

    private CExpr expr5()  throws ParseException 
    {
        CExpr result = expr6();
        if (result==null) return null;
        
        while ( true ) {
            Lex la = stream.lookahead();
            if (la.type==LexType.operator && 
                (la.value.equalsIgnoreCase("+") ||
                 la.value.equalsIgnoreCase("-")))
            {
                stream.begin();
                stream.next();
                CExpr right = expr6();
                if (right!=null) {
                    result=SumExpr.construct(result,la.value,right);
                    stream.commit();
                    continue;
                } else {
                    stream.rollback();
                }
            }
            break;
        }
        return result;
    }

    private CExpr expr6()  throws ParseException {
        CExpr result = expr7();
        if (result==null) return null;
        
        while ( true ) {
            Lex la = stream.lookahead();
            if (la.type==LexType.operator && 
                (la.value.equalsIgnoreCase("*") ||
                 la.value.equalsIgnoreCase("%") ||
                 la.value.equalsIgnoreCase("/")))
            {
                stream.begin();
                stream.next();
                CExpr right = expr7();
                if (right!=null) {
                    result=ProdExpr.construct(result,la.value,right);
                    stream.commit();
                    continue;
                } else {
                    stream.rollback();
                }
            }
            break;
        }
        return result;
    }

    private CExpr expr7()  throws ParseException {
        CExpr result = expr8();
        if (result==null) return null;
        
        while ( true ) {
            Lex la = stream.lookahead();
            if (la.type==LexType.operator && la.value.equalsIgnoreCase("^"))
            {
                stream.begin();
                stream.next();
                CExpr right = expr8();
                if (right!=null) {
                    result=new PowExpr(result,right);
                    stream.commit();
                    continue;
                } else {
                    stream.rollback();
                }
            }
            break;
        }
        return result;
    }

    private CExpr expr8() throws ParseException 
    {
        Lex la = stream.lookahead();
        if (la.type==LexType.operator && la.value.equals("+")) {
            stream.begin();
            stream.next();
            CExpr result = expr9();
            if (result!=null) {
                stream.commit();
                return result;
            }
            stream.rollback();
            return null;
        }

        if (la.type==LexType.operator && la.value.equals("-")) {
            stream.begin();
            stream.next();
            CExpr result = expr9();
            if (result!=null) {
                stream.commit();
                return new NegExpr(result);
            }
            stream.rollback();
            return null;
        }
        
        return expr9();
    }

    private CExpr expr9() throws ParseException 
    {
        Lex la = stream.lookahead();
        
        if (la.type==LexType.decimal) {
            stream.next();
            return new ConstExpr(new ClarionDecimal(la.value));
        }

        if (la.type==LexType.integer) {
            stream.next();
            return new ConstExpr(new ClarionNumber(la.value));
        }

        if (la.type==LexType.string) {
            stream.next();
            return new ConstExpr(new ClarionString(la.value));
        }
        
        if (la.type==LexType.lparam) {
            stream.begin();
            stream.next();
            CExpr contents = expr1();
            if (contents==null) {
                stream.rollback();
                error("No contents in param");
            }
            if (stream.next().type!=LexType.rparam) {
                stream.rollback();
                error("Missing ')'");
            }
            stream.commit();
            return contents;
        }

        if (la.type==LexType.label) {
            
            String label=la.value;
            
            stream.begin();
            stream.next();
            
            if (stream.lookahead().type==LexType.lparam) {
                List bits=new ArrayList();
                stream.next();
                while ( true ) {
                    CExpr param = expr1();
                    if (param==null) break;
                    bits.add(param);
                    if (stream.lookahead().type==LexType.param) {
                        stream.next();
                    } else {
                        break;
                    }
                }
                if (stream.next().type!=LexType.rparam) {
                    stream.rollback();
                    error("Missing ')'");
                }
                
                
                stream.commit();
                return new LabelExpr(label,bits); 
            }
            
            stream.commit();
            return new LabelExpr(label);
        }
        
        return null;
    }

    private Lex enforceNext(LexType type,String error) throws ParseException
    {
        Lex l = stream.next();
        if (l.type!=type) error(error);
        return l;
    }
    
    private void error(String error) throws ParseException
    {
        throw new ParseException(error);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy