2

I'm working on application which will generate VHDL code for given arithmetic expression. I decided to use ANTLR4 and JavaFX for this purpose.

So far i created grammar. It is writen for + - * / operations and integer, float numbers. But it is not alright, because it accepts for example this a = b ++++ c

grammar arithmetic;

@header {
    package generated;
}

stat
    :   VARIABLE ASSIGMENT exp      # Assigment
    ;

exp
    :   '(' exp ')'                 # Parens
    |   MINUS exp                   # UnaryMinus
    |   exp (TIMES | DIV)   exp     # MulDiv
    |   exp (PLUS  | MINUS) exp     # AddSub
    |   (VARIABLE | CONSTANT)       # Element
    ;

ASSIGMENT   :   '=' ;
PLUS        :   '+' ;
MINUS       :   '-' ;
TIMES       :   '*' ;
DIV         :   '/' ;
LPAREN      :   '(' ;
RPAREN      :   ')' ;

VARIABLE    :   LETTER                  ;
CONSTANT    :   FLOAT|INTEGER           ;

FLOAT       :   DIGIT+ ('.' DIGIT+)     ;
INTEGER     :   DIGIT+                  ;

LETTER      :   ('a' .. 'z') | ('A' .. 'Z') ;
DIGIT       :   ('0' .. '9')    ;

WS          :   [ \r\n\t] + -> channel (HIDDEN) ;

Next thing is that user should be able to modify element type, mode. So i made this UI for it. I added option for naming constants, and i will add option for setting size in bits for every element.

I'm generating table of elements (UI) from string input (in ugly way). I'm saving all elements to:

List<Element> elements = new ArrayList<>();

class Element:

public class Element {

    public enum DataTypes {
        INTEGER, POSITIVE, NATURAL, SIGNED, UNSIGNED, STD_LOGIC_VECTOR
    };

    public enum Modes {
        IN, OUT
    };

    private final String identifier;
    private final Float value;
    private final DataTypes type;
    private final Modes mode;

...

Main problem

I think that using list for saving these properties is not good approach because I will have to work with them later when I will generate VHDL code. I'm thinking about way to add them to my grammar and then possibly somehow include them to input string (maybe alter string to: a:type:mode = 4:type * b:type:mode ) from which I generate AST, or way to add them to existing AST leaves after its created.

I created visitor which extends ANTLR generated class. For now im using it for feeding generators with informations when it walks AST

public class MyVisitor extends arithmeticBaseVisitor<String> {

    private MainGenerator mainGenerator; // generate main.vhdl
    private TestGenerator testGenerator; // generate testbench.vhdl
    private List<Element> elements;

    public MyVisitor (MainGenerator mainGenerator, TestGenerator testGenerator, List<Element> elements) {
        this.mainGenerator = mainGenerator;
        this.testGenerator = testGenerator;
        this.elements = elements;
    }

In this visitor class I'm just passing that damn element list to generator :( Visitor walks the tree nodes in same order than elements are saved in list.

...

@Override
public String visitElement(ElementContext ctx) {
    passElementToGenerators();
    return null;
}

@Override
public String visitMulDiv(MulDivContext ctx) {
    visitChildren(ctx);
    //System.out.println("muldiv");
    return null;
}

...

private void passElementToGenerators () {

    Element current = elements.get(0);

    if (current.isConstant()){
        mainGenerator.addConstant(current);
        testbenchGenerator.addConstant(current);

    } else {
        mainGenerator.addSignal(current);
        testbenchGenerator.addSignal(current);
    }

    elements.remove(0);

}

...

With this generator class I'm creating vhdl code. For now just basic layout and signal/constant declarations.

public class MainGenerator {

    private FileWriter writer;
    private PrintWriter output;

    private List <Element> constants;
    private List <Element> signals;

    MainGenerator() throws IOException {
        this.writer = new FileWriter(new File(".", "main.vhdl"), false);
        this.output = new PrintWriter(writer);

        this.constants = new ArrayList<>();
        this.signals = new ArrayList<>();
    }

    ...

    private void generateEntity() {

        output.println();
        output.println("entity main is");
        output.println("\tport (");
        generateSignals("\t\t");            // generate signal declarations
        output.println("\t);");
        output.println("end main;");
    }

    ...

    private void generateSignals(String tabs) {
        for (int i = 0; i < signals.size(); i++) {
            Element signal = signals.get(i);
            output.print(tabs + "signal " + signal.getIdentifier() + ": " + signal.getMode().toString().toLowerCase() + " " + signal.getType().toString().toLowerCase());
            if( i != signals.size()-1) output.println(";");
            else output.println();
        }
    }

Generated file looks like this:

library IEEE;
use IEEE.std_logic_1164.all

entity main is
    port (
        signal a: out integer;
        signal b: in unsigned;
        signal x: in std_logic_vector
    );
end main;

architecture behavioral of main is

    constant constant: signed := 4.0

begin


end behavioral;

I have no experience building compiler nor working with ANTLR, and I think I'm doing it wrong. When it comes to much harder things like declarations - dividing expression to processes I will be lost. (a = b + c * 2 => code block for multiplication c * 2 => and next process block for addition... + b)

This is my first question - in fact more questions. I hope its not too long, but i feel that my project background was necessary.

Thanks for any suggestions or advices. If is something wrong with my question, let me know I'll try to edit it.

Samuel
  • 19
  • 4

0 Answers0