EllErre is designed to be an LR automata generator, with the following algorithms:
- [X] First Set
- [X] Follow Set
- [X] LR(0) automata / SLR(1) automata
- [X] LR(1) automata
- [X] LALR(1) automata
- [X] GraphViz automata representation
- [X] Mark initial and end states in the automata
- [X] Step by Step GraphViz automata representation for LR0/LR1
- [ ] Step by Step GraphViz automata representation for LALR1
- [ ] Detect shift/reduce and reduce/reduce conflicts
- [ ] LR Analysis for a given input
It is current in development.
For now, it calculates the First/Follow sets, the LR(0), LR(1) and LALR(1) automatas for a given grammar.
sudo apt-get install git cmake build-essential flex bison libfl-dev;
git clone https://github.com/schnorr/ellerre.git ; mkdir -p ellerre/b ; cd ellerre/b ; cmake .. ; make
- If you want to visualize the automatas with graphviz
sudo apt-get install graphviz
mkdir -p build ; cd build ; cmake .. ; make
-- The C compiler identification is GNU 7.3.0 -- The CXX compiler identification is GNU 7.3.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Found FLEX: /usr/bin/flex (found version "2.6.4") -- Found BISON: /usr/bin/bison (found version "3.0.4") -- Configuring done -- Generating done -- Build files have been written to: /tmp/ellerre/build [ 11%] [BISON][parser] Building parser with bison 3.0.4 [ 22%] [FLEX][scanner] Building scanner with flex 2.6.4 Scanning dependencies of target ellerre [ 33%] Building CXX object CMakeFiles/ellerre.dir/src/main.cc.o [ 44%] Building CXX object CMakeFiles/ellerre.dir/src/symbol.cc.o [ 55%] Building CXX object CMakeFiles/ellerre.dir/src/rule.cc.o [ 66%] Building CXX object CMakeFiles/ellerre.dir/src/grammar.cc.o [ 66%] [BISON][parser] Building parser with bison 3.0.4 [ 77%] Building CXX object CMakeFiles/ellerre.dir/scanner.cc.o [ 88%] Building CXX object CMakeFiles/ellerre.dir/parser.cc.o [100%] Linking CXX executable ellerre [100%] Built target ellerre
cd build
./firstfollow < ../examples/ex1.ee
Grammar with 3 rules and 4 symbols (2 non-terminals): S => A A A => a A A => b First sets: S -- b a A -- b a Follow sets: S -- $ A -- $ b a
cd build
./lr0 < ../examples/ex1.ee
Grammar with 4 rules and 4 symbols (2 non-terminals): S' ⇒ S S ⇒ A A A ⇒ a A A ⇒ b LR0 item set: S' ⇒ • S S' ⇒ S • S ⇒ • A A S ⇒ A • A S ⇒ A A • A ⇒ • a A A ⇒ a • A A ⇒ a A • A ⇒ • b A ⇒ b • LR0 automata: State 0: S' ⇒ • S --------------- S ⇒ • A A A ⇒ • a A A ⇒ • b Transitions: S ---> 1 A ---> 2 b ---> 3 a ---> 4 State 1: S' ⇒ S • --------------- State 2: S ⇒ A • A --------------- A ⇒ • a A A ⇒ • b Transitions: A ---> 5 b ---> 3 a ---> 4 State 3: A ⇒ b • --------------- State 4: A ⇒ a • A --------------- A ⇒ • a A A ⇒ • b Transitions: A ---> 6 b ---> 3 a ---> 4 State 5: S ⇒ A A • --------------- State 6: A ⇒ a A • ---------------
cd build
./lr1 < ../examples/ex1.ee
Grammar with 4 rules and 4 symbols (2 non-terminals): S' => S S => A A A => a A A => b First set: S -- b a A -- b a S' -- b a Follow set: S -- $ A -- $ b a S' -- $ LR1 item set: S' => • S , $ S' => S • , $ S => • A A , $ S => A • A , $ S => A A • , $ A => • a A , $ A => • a A , b A => • a A , a A => a • A , $ A => a • A , b A => a • A , a A => a A • , $ A => a A • , b A => a A • , a A => • b , $ A => • b , b A => • b , a A => b • , $ A => b • , b A => b • , a LR1 automata: State 0: S' => • S , $ --------------- S => • A A , $ A => • a A , b A => • a A , a A => • b , b A => • b , a Transitions: S ---> 1 A ---> 2 b ---> 3 a ---> 4 State 1: S' => S • , $ --------------- State 2: S => A • A , $ --------------- A => • a A , $ A => • b , $ Transitions: A ---> 5 b ---> 6 a ---> 7 State 3: A => b • , b A => b • , a --------------- State 4: A => a • A , b A => a • A , a --------------- A => • a A , b A => • a A , a A => • b , b A => • b , a Transitions: A ---> 8 b ---> 3 a ---> 4 State 5: S => A A • , $ --------------- State 6: A => b • , $ --------------- State 7: A => a • A , $ --------------- A => • a A , $ A => • b , $ Transitions: A ---> 9 b ---> 6 a ---> 7 State 8: A => a A • , b A => a A • , a --------------- State 9: A => a A • , $ ---------------
cd build
./lalr1 < ../examples/ex1.ee
Grammar with 4 rules and 4 symbols (2 non-terminals): S' => S S => A A A => a A A => b First set: S -- b a A -- b a S' -- b a Follow set: S -- $ A -- $ b a S' -- $ LALR1 item set: S' => • S , $ S' => S • , $ S => • A A , $ S => A • A , $ S => A A • , $ A => • a A , $ A => • a A , b A => • a A , a A => a • A , $ A => a • A , b A => a • A , a A => a A • , $ A => a A • , b A => a A • , a A => • b , $ A => • b , b A => • b , a A => b • , $ A => b • , b A => b • , a LALR1 automata: State 0: S' => • S , $ --------------- S => • A A , $ A => • a A , b A => • a A , a A => • b , b A => • b , a Transitions: S ---> 1 A ---> 2 b ---> 3 a ---> 4 State 1: S' => S • , $ --------------- State 2: S => A • A , $ --------------- A => • a A , $ A => • b , $ Transitions: A ---> 5 b ---> 3 a ---> 4 State 3: A => b • , $ A => b • , b A => b • , a --------------- State 4: A => a • A , $ A => a • A , b A => a • A , a --------------- A => • a A , $ A => • a A , b A => • a A , a A => • b , $ A => • b , b A => • b , a Transitions: A ---> 6 b ---> 3 a ---> 4 State 5: S => A A • , $ --------------- State 6: A => a A • , $ A => a A • , b A => a A • , a ---------------
Each parser execution from EllErre generate a .dot file after its execution. The dot files are named after its parsing algorithm (LR0.dot, LR1.dot, and LALR1.dot).
This files can be used by tools like graphviz to generate a visual representation of the given LR automata.
The following execution generates the “LR0.dot” file, which describes the automata in the using the .dot syntax.
cd build
./lr0 < ../examples/ex1.ee >> /dev/null
cat LR0.dot
digraph g { graph [fontsize=30 labelloc="t" label="" splines=true overlap=false rankdir = "LR"]; ratio = auto; "state0" [ style = "filled" penwidth = 1 fillcolor = "white" fontname = "Courier New" shape = "Mrecord" label = <<table border="0" cellborder="0" cellpadding="3" bgcolor="white"> <tr><td bgcolor="black" align="center" colspan="2"><font color="white">State #0</font></td></tr> <tr><td align="left" port="r0"><font face="bold">S' ⇒ • S </font></td></tr> <tr><td align="left" port="r1"><font color="gray25" face="bold">S ⇒ • A A </font></td></tr> <tr><td align="left" port="r2"><font color="gray25" face="bold">A ⇒ • a A </font></td></tr> <tr><td align="left" port="r3"><font color="gray25" face="bold">A ⇒ • b </font></td></tr> </table>>]; "state1" [ style = "filled" penwidth = 1 fillcolor = "white" fontname = "Courier New" shape = "Mrecord" label = <<table border="0" cellborder="0" cellpadding="3" bgcolor="white"> <tr><td bgcolor="black" align="center" colspan="2"><font color="white">State #1</font></td></tr> <tr><td align="left" port="r0"><font face="bold">S' ⇒ S • </font></td></tr> </table>>]; "state2" [ style = "filled" penwidth = 1 fillcolor = "white" fontname = "Courier New" shape = "Mrecord" label = <<table border="0" cellborder="0" cellpadding="3" bgcolor="white"> <tr><td bgcolor="black" align="center" colspan="2"><font color="white">State #2</font></td></tr> <tr><td align="left" port="r0"><font face="bold">S ⇒ A • A </font></td></tr> <tr><td align="left" port="r1"><font color="gray25" face="bold">A ⇒ • a A </font></td></tr> <tr><td align="left" port="r2"><font color="gray25" face="bold">A ⇒ • b </font></td></tr> </table>>]; "state3" [ style = "filled" penwidth = 1 fillcolor = "white" fontname = "Courier New" shape = "Mrecord" label = <<table border="0" cellborder="0" cellpadding="3" bgcolor="white"> <tr><td bgcolor="black" align="center" colspan="2"><font color="white">State #3</font></td></tr> <tr><td align="left" port="r0"><font face="bold">A ⇒ b • </font></td></tr> </table>>]; "state4" [ style = "filled" penwidth = 1 fillcolor = "white" fontname = "Courier New" shape = "Mrecord" label = <<table border="0" cellborder="0" cellpadding="3" bgcolor="white"> <tr><td bgcolor="black" align="center" colspan="2"><font color="white">State #4</font></td></tr> <tr><td align="left" port="r0"><font face="bold">A ⇒ a • A </font></td></tr> <tr><td align="left" port="r1"><font color="gray25" face="bold">A ⇒ • a A </font></td></tr> <tr><td align="left" port="r2"><font color="gray25" face="bold">A ⇒ • b </font></td></tr> </table>>]; "state5" [ style = "filled" penwidth = 1 fillcolor = "white" fontname = "Courier New" shape = "Mrecord" label = <<table border="0" cellborder="0" cellpadding="3" bgcolor="white"> <tr><td bgcolor="black" align="center" colspan="2"><font color="white">State #5</font></td></tr> <tr><td align="left" port="r0"><font face="bold">S ⇒ A A • </font></td></tr> </table>>]; "state6" [ style = "filled" penwidth = 1 fillcolor = "white" fontname = "Courier New" shape = "Mrecord" label = <<table border="0" cellborder="0" cellpadding="3" bgcolor="white"> <tr><td bgcolor="black" align="center" colspan="2"><font color="white">State #6</font></td></tr> <tr><td align="left" port="r0"><font face="bold">A ⇒ a A • </font></td></tr> </table>>]; state0 -> state1[ penwidth = 3 fontsize = 22 fontcolor = "black" label = "S" ]; state0 -> state2[ penwidth = 3 fontsize = 22 fontcolor = "black" label = "A" ]; state0 -> state3[ penwidth = 3 fontsize = 22 fontcolor = "black" label = "b" ]; state0 -> state4[ penwidth = 3 fontsize = 22 fontcolor = "black" label = "a" ]; state2 -> state5[ penwidth = 3 fontsize = 22 fontcolor = "black" label = "A" ]; state2 -> state3[ penwidth = 3 fontsize = 22 fontcolor = "black" label = "b" ]; state2 -> state4[ penwidth = 3 fontsize = 22 fontcolor = "black" label = "a" ]; state4 -> state6[ penwidth = 3 fontsize = 22 fontcolor = "black" label = "A" ]; state4 -> state3[ penwidth = 3 fontsize = 22 fontcolor = "black" label = "b" ]; state4 -> state4[ penwidth = 3 fontsize = 22 fontcolor = "black" label = "a" ]; }
cd build
dot -Tpng LR0.dot -o LR0_output.png
Alternatively, you can use: https://ellerre.herokuapp.com/
There, you can input a .dot file that defines a grammar or textually input your grammar, separating each line by a “;” . You can also download the visualizations generated.
The application was created using the Shiny package for R, and the source code is available in: ./ellerre-web
The LR0 and LR1 execution generate a file “LR0-step.dot” or “LR1-step.dot”, which is used by the Python script for the step-by-step visualization. It was created with Python 3.7.5.
Install the Python libraries needed (suggestion to use a conda environment):
conda create --name ellerre-env python=3.7.3
conda activate ellerre-env
sudo apt-get install graphviz graphviz-dev
pip install pygraphviz
pip install tk
pip install Pillow
To launch the Python script, you can input the step .dot file or load it using the GUI menu. You can also save the generated images step by step using the menu -> File option.
python run-steps.py build/LR0-steps.dot
The program renders the step files using the .dot type, with positions
set automatically. You can use fixed nodes position by passing the fdp
argument to the execution, as follows.
python run-steps.py build/LR0-steps.dot fdp
If you use the EllErre information, please cite as:
@software{ellerre, title = {EllErre: an LR automata generator}, author = {Schnorr, L. M. and Miletto, M. C. and Solórzano A. L. V.}, year = 2020, url = {https://github.com/schnorr/ellerre} }
[Software] L. M. Schnorr, M. C. Miletto, and A. L. V. Solórzano, EllErre: an LR automata generator, 2020. URL: https://github.com/schnorr/ellerre