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.