net.udidb.expr.lang.c.CExpressionCompiler.java Source code

Java tutorial

Introduction

Here is the source code for net.udidb.expr.lang.c.CExpressionCompiler.java

Source

/*
 * Copyright (c) 2011-2015, Dan McNulty
 * All rights reserved.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package net.udidb.expr.lang.c;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeProperty;
import org.antlr.v4.runtime.tree.Tree;
import org.antlr.v4.runtime.tree.gui.TreeTextProvider;
import org.antlr.v4.runtime.tree.gui.TreeViewer;
import org.antlr.v4.runtime.tree.gui.TreeViewer.DefaultTreeTextProvider;

import com.google.common.annotations.VisibleForTesting;

import net.libudi.api.exceptions.UdiException;
import net.sourcecrumbs.api.debug.symbols.Function;
import net.udidb.expr.ExecutionContext;
import net.udidb.expr.ExpressionException;
import net.udidb.expr.Expression;
import net.udidb.expr.ExpressionCompiler;
import net.udidb.expr.grammar.c.CLexer;
import net.udidb.expr.grammar.c.CParser;
import net.udidb.expr.stubs.StubExecutionContext;
import net.udidb.expr.values.ExpressionValue;

/**
 * An expression compiler for C
 *
 * @author mcnulty
 */
public class CExpressionCompiler implements ExpressionCompiler {
    @Override
    public Expression compile(String expression, ExecutionContext executionContext) throws ExpressionException {
        try {
            return compile(expression, executionContext, false);
        } catch (ParseCancellationException e) {
            throw new ExpressionException(e);
        }
    }

    @Override
    public Expression compile(String expression) throws ExpressionException {
        try {
            return compile(expression, new StubExecutionContext());
        } catch (ParseCancellationException e) {
            throw new ExpressionException(e);
        }
    }

    @VisibleForTesting
    Expression compile(String expression, ExecutionContext executionContext, boolean displayTree)
            throws ExpressionException {
        long pc = 0;
        Function currentFunction = null;
        if (!executionContext.getCurrentThread().getParentProcess().isWaitingForStart()) {
            try {
                pc = executionContext.getCurrentThread().getPC();
            } catch (UdiException e) {
                throw new ExpressionException(e);
            }
            currentFunction = executionContext.getExecutable().getContainingFunction(pc);
        }

        final ParseTreeProperty<NodeState> states = new ParseTreeProperty<>();

        // Parse the expression
        final CParser parser;
        try {
            parser = createParser(expression);
        } catch (IOException e) {
            throw new ExpressionException(e);
        }
        ParserRuleContext parseTree = parser.expression();

        // Resolve all symbols, interrogating the debuggee as necessary
        resolveSymbols(parseTree, states, executionContext, currentFunction, pc);

        // Type checking
        typeCheckExpression(parseTree, states);

        // Simplify the expression given the current state of the AST
        simplifyExpression(parseTree, states, executionContext);

        // Generate code and produce Expression to encapsulate the result
        Expression output = generateCode(parseTree, states, executionContext);

        if (displayTree) {
            TreeViewer viewer = new TreeViewer(Arrays.asList(parser.getRuleNames()), parseTree);
            viewer.setTreeTextProvider(new TreeTextProvider() {
                TreeTextProvider defaultProvider = new DefaultTreeTextProvider(
                        Arrays.asList(parser.getRuleNames()));

                @Override
                public String getText(Tree node) {
                    if (node instanceof ParseTree) {
                        NodeState nodeState = states.get((ParseTree) node);

                        ExpressionValue value;
                        if (nodeState != null) {
                            value = nodeState.getExpressionValue();
                        } else {
                            value = null;
                        }

                        if (value != null) {
                            return defaultProvider.getText(node) + "(" + value + ")";
                        } else {
                            return defaultProvider.getText(node) + "(null)";
                        }
                    }

                    return defaultProvider.getText(node);
                }
            });
            viewer.open();
        }

        return output;
    }

    @VisibleForTesting
    static void resolveSymbols(ParserRuleContext parseTree, ParseTreeProperty<NodeState> states,
            ExecutionContext executionContext, Function currentFunction, long pc) {
        SymbolResolutionVisitor resolutionVisitor = new SymbolResolutionVisitor(states, executionContext,
                currentFunction, pc);
        parseTree.accept(resolutionVisitor);
    }

    @VisibleForTesting
    static void typeCheckExpression(ParserRuleContext parseTree, ParseTreeProperty<NodeState> states) {
        TypeCheckingVisitor typeCheckingVisitor = new TypeCheckingVisitor(states);
        parseTree.accept(typeCheckingVisitor);
    }

    @VisibleForTesting
    static void simplifyExpression(ParserRuleContext parseTree, ParseTreeProperty<NodeState> states,
            ExecutionContext executionContext) {
        ExpressionSimplificationVisitor visitor = new ExpressionSimplificationVisitor(states, executionContext);
        parseTree.accept(visitor);
    }

    @VisibleForTesting
    static Expression generateCode(ParserRuleContext parseTree, ParseTreeProperty<NodeState> states,
            ExecutionContext executionContext) {
        CodeGenVisitor visitor = new CodeGenVisitor(states, executionContext);
        return parseTree.accept(visitor);
    }

    private static CParser createParser(String expression) throws IOException {
        ANTLRInputStream inputStream = new ANTLRInputStream(
                new ByteArrayInputStream(expression.getBytes(StandardCharsets.UTF_8)));
        CLexer lexer = new CLexer(inputStream);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        return new CParser(tokens);
    }

    @VisibleForTesting
    static ParserRuleContext createParseTree(String expression) throws IOException {
        return createParser(expression).expression();
    }
}