SMPL is a small, but expressive math programming language.
I was introduced to Compiler Design by Prof. Daniel Coore in my final year while doing Undergraduate studies for Computer Science and Electronics degree at the University of the West Indies, Mona. It's the most memorable project that I have had while studying at the university. Herein is an updated version of building that project. I have made a few modification to the original specification provided by Prof. Coore and the result of the modifications are found here.
Prof. Coore mentioned that his initial specification was inspired by Scheme. Scheme is inspired by Lisp. Some of the modifications are inspired by JavaScript. The plan is to maintain the language as loosely typed language.
This compiler project is built on the Java platform and uses JFlex and CUP tools. While conducting researching and developing the project, I was fascinated by other compiler design tools such as the Lex & Yacc tools (or, better yet, Flex & Bison+). Apparently JFlex and CUP was modeled off flex and bison (formerly lex and yacc) that is, in my opinion, far more superior than any other tool in this genre simply because of the language used: C. With C, you can build more native machine applications rather than depending on a virtual machine or language runtime environment.
ANTLR [+] also caught my attention. It's main selling point seems to be that it can be used in many of the popular programming languages. Nonetheless, for the experienced programmer, this isn't enough to influence a decision to use it.
- Java 11 SDK
- JFlex
- CUP
- JUnit 5
- Ant 1.10.7
Download your preferred version of smpl-coore-outar-x-x-x.jar file in the releases section. Transfer that file into your lib folder from which your Java compiler will read and understand.
For Java Projects created in VS Code such as this, you can transfer the file into the lib folder found at the root of the project.
When compiling in the terminal, reference must be made to this jar file and the java-cup-11b.jar file in the javac command. For example,
javac -cp lib/smpl-coore-outar-1.0.1.jar src/App.java
You will also need to make reference to these dependecies To run the generated class file as follows,
java -cp lib/smpl-coore-outar-1.0.1.jar src/App
N.B. For version 1.0.0, reference must be made to the java-cup-11b.jar file. Since version 1.0.1, the java-cup-11b.jar file has been bundled into smpl-coore-outar-x.x.x.jar file.
SMPL can be used through an interactive shell or by passing a folder path or a set of file paths to the App class. All the class and function definitions can be accessed from the SMPL (smpl-coore-outar-x-x-x.jar) library.
Once you have completed installation of SMPL (smpl-coore-outar-x-x-x.jar) library, you can try the snippet of Java code shown below,
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.io.ByteArrayInputStream;
import java.util.Hashtable;
import java_cup.runtime.Symbol;
import smpl.lang.SMPLLexer;
import smpl.lang.SMPLParser;
import smpl.sys.Program;
import smpl.sys.values.IValue;
public class App {
public static void main(String[] args) throws Exception {
System.out.println("Hello, World! Trying out SMPL");
Hashtable<String, IValue> heap = new Hashtable<String, IValue>();
String myExpression = "v = 8; :> v * 4;"; // Output: 32
InputStream in = new ByteArrayInputStream(myExpression.getBytes(StandardCharsets.UTF_8));
SMPLLexer lexer = new SMPLLexer( new InputStreamReader(in) );
SMPLParser p = new SMPLParser(lexer);
Symbol parseResult = p.parse();
Program program = (Program)parseResult.value;
program.execute( heap );
}
}
Now, once this works well for you, you can begin tinkering with SMPL by trying out the examples listed and documented here.
A few examples of using SMPL syntax can be seen in the snippet below, which was extracted from examples,
fact = (:n) { (n <= 1) ? 1 : n * fact( n - 1 ); }
// To get a better approximation for cos(r), you need more terms in your Taylor polynomial.
sin = (:n) {
r = ( n / 180.0 ) * π;
v = r - ( (r**3)/fact(3) ) + ( (r**5)/fact(5) ) - ( (r**7)/fact(7) ) + ( (r**9)/fact(9) ) - ( (r**11)/fact(11) );
v;
}
cos = (:n) {
r = ( n / 180.0 ) * π;
v = 1 - ( (r**2)/fact(2) ) + ( (r**4)/fact(4) ) - ( (r**6)/fact(6) ) + ( (r**8)/fact(8) ) - ( (r**10)/fact(10) );
v;
}
tan = (:n) {
t = sin(n) ÷ √( 1 - sin(n)**2 );
t;
}
:> "Sine of 30 degrees is ${ sin(30) }\n";
:> "Cosine of 30 degrees is ${ cos(30) }\n";
:> "Tangent of 30 degrees is ${ tan(30) }\n";
Yet another snippet extracted from examples can be seen below.
:> "Step by 1\n";
(i = 1; i <= 9; i++) {
:> i * (3 + i);:> "\n";
}
:> "Step by 2\n";
(i = 1; i < 9; i+=2) {
:> i * (3 + i);:> "\n";
}
q = 5;
(; q > 1; q--) {
:> "Rebel ${q}";
:> "\n";
}
q = 3;
(; q > 1;) {
:> "Boom ... ${q}";
:> "\n";
q--;
}
/*
(;;) {
:> "Ooh lala"; :> "\n";
}
*/
To use the SMPL interactive shell, you must perform the following command (assuming that the dependencies are in a lib folder within the folder that you are running the command),
java -cp lib/smpl-coore-outar-1.0.1.jar App
You can exit the interactive shell by entering exit
or quit
and then press ENTER.
To read a folder containing text files with extension .smpl, perform the following command (assuming examples is the path of folder within the folder that you are running the command),
java -cp lib/smpl-coore-outar-1.0.1.jar App examples
To read a file containing SMPL syntax (no strict filtering done for file path arguments), perform the following command,
java -cp lib/smpl-coore-outar-1.0.1.jar App myplayground.smpl
For multiple files,
java -cp lib/smpl-coore-outar-1.0.1.jar App identifiers.smpl hypotenuse.smpl
Contributions are welcomed to this project. It is expected that you make a fork of this repo, make the changes that you request and then create a pull request, where your changes can be reviewed for merging into the main branch.
It is expected that prospective contributors acquaint themselves with an understanding of the code convention, the application's architecture and the way how this software works before contributing via pull request. There should be enough documentation in this repo through README files that can inform the prospective contributor.
The workspace contains several folders, where:
src
: all source codesmpl
: core functions for the SMPL interpretertests
: contains SMPL JUnit tests
examples
: contains several documented examples and snippets of SMPL syntax in .smpl text fileslib
: maintains dependenciesbin
: contains generated class files from compilationdocs
: contains generated HTML and XML files from javadoc and junitreport.attachments
: contains media for README documentation.vscode
: VS Code configuration.github
: GitHub Actions CI workflow
The JAVA DEPENDENCIES
view allows you to manage your dependencies. More details can be found here.
JFlex is found in the Aptitude package repository and can be downloaded for use on Ubuntu/Debian machines by performing the following command,
sudo apt install jflex
If making changes to the lexer to add or modify a new token, the Java file can be generated by navigating to the src
folder and performing the following command,
jflex src/smpl/lang/SMPLLexer.flex -d src/smpl/lang
Details of using JFlex can be found here.
Details for using the CLI are accessible by performing the following,
jflex --help
If changes are required to the grammar, the contributor can look at the .cup file, acquaint themself with the LALR CUP language found here and perform the following command to generate the new Parser,
java -jar lib/java-cup-11b.jar -interface -destdir src/smpl/lang -parser SMPLParser src/smpl/lang/SMPLParser.cup
Details for using the CLI are accessible by performing the following,
java -jar lib/java-cup-11b.jar -help
The Ant build tool is used to automate a number of possibilities. The build.xml is configured to:
- Generate the lexer
- Generate the parser
- Compile the core source code
- Generate a new smpl-coore-outar-x-x-x.jar file
- Generate updated HTML documentation
- Perform unit tests
- Generate unit tests reports
- Perform SMPL examples
Before we can use ant, ensure that it is installed by performing the following,
ant --version
If it is not installed, you can install ant on Ubuntu/Debian machine by performing the following,
sudo apt-get install ant
In order to perform all the possibilities, perform the following in the root folder that contains build.xml,
ant
For just compiling the project, perform the following,
ant compile
To generate the class library, smpl-coore-outar-x-x-x.jar, perform the following,
ant build-lib
For performing the unit tests, perform the following,
ant test
To remove the generated bin and docs folder, perform the following,
ant clean
Run JUnit tests 😓 🧪
java -jar lib/junit-platform-console-standalone-1.8.0.jar -cp bin --include-engine=junit-jupiter --scan-classpath
- Compilers: Principles, Techniques and Tools by Alfred V. Aho, Ravi Sethi and Jeffrey D. Ullman
- Compiler Design in C by Allen I. Hobub
- flex & bison by John Levine
- Implementing String Interpolation in Flex & Bison - StackOverflow
- Ant: The Definitive Guide by Steve Holzner
- Building and testing Java with Ant