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

yajco.generator.parsergen.beaver.BeaverParserGenerator Maven / Gradle / Ivy

Go to download

YAJCo - Yet Another Java Compiler Compiler - object oriented language specification - beaver parser generator

The newest version!
package yajco.generator.parsergen.beaver;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import yajco.model.pattern.impl.Associativity;
import yajco.generator.parsergen.beaver.semlang.translator.SemLangToJavaTranslator;
import yajco.grammar.NonterminalSymbol;
import yajco.grammar.Symbol;
import yajco.grammar.TerminalSymbol;
import yajco.grammar.bnf.Alternative;
import yajco.grammar.bnf.Grammar;
import yajco.grammar.bnf.Production;
import yajco.grammar.translator.YajcoModelToBNFGrammarTranslator;
import yajco.model.Language;
import yajco.model.pattern.impl.Operator;
import yajco.model.type.ArrayType;
import yajco.model.type.ComponentType;
import yajco.model.type.ListType;
import yajco.model.type.PrimitiveType;
import yajco.model.type.ReferenceType;
import yajco.model.type.SetType;
import yajco.model.type.Type;
import yajco.model.utilities.Utilities;

public class BeaverParserGenerator {

    public static final String DEFAULT_PACKAGE_NAME = "parser.beaver";
    public static final String PARSER_CLASS_NAME_PREFIX = "LALR";
    public static final String PARSER_CLASS_NAME_SUFFIX = "Parser";
    private static final BeaverParserGenerator instance = new BeaverParserGenerator();
    private Language language;
    private Grammar grammar;
    private Set usedTerminals;
    private Set operatorTerminalsUsed;
    private Map operatorAlternativesMap;
    private String parserPackageName;
    private String parserClassName;

    private BeaverParserGenerator() {
    }

    public void generateFrom(Language language, Grammar grammar, String parserPackageName, String parserClassName, PrintStream writer) {
        this.language = language;
        this.grammar = grammar;
        this.operatorTerminalsUsed = new HashSet();
        this.operatorAlternativesMap = new HashMap();
        this.parserPackageName = parserPackageName;
        this.parserClassName = parserClassName;
        
        usedTerminals = getUsedTerminals();

        writePackage(writer);
        writeClass(writer);
        writeImports(writer);

        writeTerminals(writer);

        writeOperatorsSpecification(writer);

        writeTypes(writer);

        writeGoal(writer);

        writeGrammar(writer);
    }

    private void writePackage(PrintStream writer) {
        //parserPackageName = language.getName() != null ? language.getName() + "." + DEFAULT_PACKAGE_NAME : DEFAULT_PACKAGE_NAME;

        writer.println("%package \"" + parserPackageName + "\";");
    }

    private void writeClass(PrintStream writer) {
        //String className = PARSER_CLASS_NAME_PREFIX + grammar.getStartSymbol().getName() + PARSER_CLASS_NAME_SUFFIX;

        writer.println("%class \"" + parserClassName + "\";");
    }

    private void writeImports(PrintStream writer) {
//		for (Concept concept : language.getConcepts()) {
//			writer.println("%import \"" + Utilities.getFullConceptClassName(language, concept) + "\";");
//		}
        writer.println("%import \"" + parserPackageName + ".SymbolListImpl\";");
        //DOMINIK TEST
        writer.println("%import \"" + parserPackageName + ".SymbolWrapper\";");
        // END
        writer.println();
    }

    private void writeTerminals(PrintStream writer) {
        writer.print("%terminals ");

        List terminals = new ArrayList(usedTerminals);
        for (int i = 0; i < terminals.size(); i++) {
            writer.print(terminals.get(i).getName());
            if (i != (terminals.size() - 1)) {
                writer.print(", ");
            }
        }
        writer.println(";");
        writer.println();
    }

    private void writeOperatorsSpecification(PrintStream writer) {
        List priorities = new ArrayList(grammar.getOperatorPool().keySet());
        Collections.sort(priorities);

        if (priorities.isEmpty()) {
            return;
        }

        List specifications = new ArrayList(priorities.size());
        for (Integer priority : priorities) {
            String specification = operatorSpecificationToString(priority);
            if (specification != null) {
                specifications.add(specification);
            }
        }

        Collections.reverse(specifications);
        for (String specification : specifications) {
            writer.println(specification);
        }
        writer.println();
    }

    private void writeTypes(PrintStream writer) {
        for (TerminalSymbol terminal : usedTerminals) {
            if (terminal.getName().startsWith(YajcoModelToBNFGrammarTranslator.DEFAULT_SYMBOL_NAME)) {
                continue;
            }

            writer.println("%typeof " + terminal.getName() + " = \"java.lang.String\";");
        }

        for (NonterminalSymbol nonterminal : grammar.getNonterminals().values()) {
            //DOMINIK UPRAVA
            writer.println("%typeof " + nonterminal.getName() + " = \"" + parserPackageName + ".SymbolWrapper<" + typeToString(nonterminal.getReturnType()) + ">\";");
            //writer.println("%typeof " + nonterminal.getName() + " = \"" + typeToString(nonterminal.getReturnType()) + "\";");
        }
        writer.println();
    }

    private void writeGoal(PrintStream writer) {
        writer.println("%goal " + grammar.getStartSymbol().getName() + ";"); //povodne
        writer.println();
    }

    private void writeGrammar(PrintStream writer) {
        for (Production production : grammar.getProductions().values()) {
            writeProduction(production, writer);
        }
    }

    private void writeProduction(Production production, PrintStream writer) {
        writer.println(production.getLhs().getName());

        for (int i = 0; i < production.getRhs().size(); i++) {
            writer.print(i == 0 ? "\t= " : "\t| ");
            writeAlternative(production.getRhs().get(i), writer);
            writer.println();
        }
        writer.println("\t;");
        writer.println();
    }

    private void writeAlternative(Alternative alternative, PrintStream writer) {
        for (int i = 0; i < alternative.getSymbols().size(); i++) {
            Symbol symbol = alternative.getSymbols().get(i);
            writer.print(symbol.getName());
            if (symbol.getVarName() != null) {
                writer.print(".");
                writer.print(symbol.getVarName());
            }
            if (i != (alternative.getSymbols().size() - 1)) {
                writer.print(" ");
            }
        }

        if (operatorAlternativesMap.containsKey(alternative)) {
            writer.print(" @ " + operatorAlternativesMap.get(alternative));
        }

        writer.print("\t{: ");
        SemLangToJavaTranslator.getInstance().translateActions(alternative.getActions(), language, writer);
        writer.print(":}");
    }

    private String operatorSpecificationToString(Integer priority) {
        List opAlternatives = grammar.getOperatorPool().get(priority);
        if (opAlternatives.isEmpty()) {
            return null;
        }
        Operator opPattern = (Operator) opAlternatives.get(0).getPattern(Operator.class);

        int counter = 1;
        StringBuilder builder = new StringBuilder();
        builder.append("%").append(associativityToString(opPattern.getAssociativity())).append(" ");
        for (Alternative alternative : opAlternatives) {
            for (Symbol symbol : alternative.getSymbols()) {
                if (symbol instanceof NonterminalSymbol) {
                    continue;
                }

                TerminalSymbol terminal = (TerminalSymbol) symbol;
                if (!operatorTerminalsUsed.contains(terminal)) {
                    operatorTerminalsUsed.add(terminal);
                    builder.append(terminal.getName()).append(", ");
                } else {
                    String precSpec = "PREC_" + priority + "_" + counter++;
                    builder.append(precSpec).append(", ");
                    operatorAlternativesMap.put(alternative, precSpec);
                }
            }
        }

        if (builder.toString().endsWith(", ")) {
            builder.setLength(builder.length() - 2);
        }
        builder.append(";");

        return builder.toString();
    }

    private String associativityToString(Associativity associativity) {
        switch (associativity) {
            case LEFT:
                return "left";
            case NONE:
                return "nonassoc";
            case RIGHT:
                return "right";
            case AUTO:
                System.out.println("AUTO associativity set to LEFT without any analyse!!!");
                return "left";
            default:
                throw new IllegalArgumentException("Cann't resolve associativity!");
        }
    }

    private String typeToString(Type type) {
        if (type instanceof PrimitiveType) {
            return primitiveTypeToString((PrimitiveType) type);
        } else if (type instanceof ReferenceType) {
            ReferenceType refType = (ReferenceType) type;
            return Utilities.getFullConceptClassName(language, refType.getConcept());
        } else if (type instanceof ComponentType) {
            ComponentType innerType = (ComponentType) type;
            //DOMINIK TEST
            String innerTypeString = typeToString(innerType.getComponentType());
            //String innerTypeString = typeToStringWrapped(innerType.getComponentType()); - MOJE

            if (type instanceof ArrayType) {
                return innerTypeString + "[]";
            } else if (type instanceof ListType) {
                // problem v beaver-i sposobuje nutnost tohoto riadku
                return parserPackageName + ".SymbolListImpl" + "<" + innerTypeString + ">";
                //return "java.util.List<" + innerTypeString + ">";
            } else if (type instanceof SetType) {
                return "java.util.Set<" + innerTypeString + ">";
            } else {
                throw new IllegalArgumentException("Unknown component type detected: '" + type.getClass().getCanonicalName() + "'!");
            }
        } else {
            throw new IllegalArgumentException("Unknown type detected: '" + type.getClass().getCanonicalName() + "'!");
        }
    }

    private String primitiveTypeToString(PrimitiveType type) {
        switch (type.getPrimitiveTypeConst()) {
            case BOOLEAN:
                return "java.lang.Boolean";
            case INTEGER:
                return "java.lang.Integer";
            case REAL:
                return "java.lang.Float";
            case STRING:
                return "java.lang.String";

            default:
                throw new IllegalArgumentException("Unknown primitive type '" + type.toString() + "'!");
        }
    }
    private Set getUsedTerminals() {
        return getUsedTerminals(grammar);
    }

    public static Set getUsedTerminals(Grammar grammar) {
        Set terminals = new HashSet();
        for (Production production : grammar.getProductions().values()) {
            for (Alternative alternative : production.getRhs()) {
                for (Symbol symbol : alternative.getSymbols()) {
                    if (symbol instanceof TerminalSymbol){
                        TerminalSymbol ts = (TerminalSymbol)symbol;
                        if (grammar.getTerminalPool().containsKey(ts)) {
                            terminals.add(ts);
                        }
                    }
                }
            }
        }
        return terminals;
    }

    public static BeaverParserGenerator getInstance() {
        return instance;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy