From da61cc67e73054eee18b2a8db7a29ed0de765550 Mon Sep 17 00:00:00 2001 From: jwansek Date: Mon, 11 Oct 2021 15:52:41 +0100 Subject: removed pushing bytecode --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 8e5c216..3f7cb11 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +*.class + # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 -- cgit v1.2.3 From 9ce3bc07fc567594c0ceb22386799ec59e9dfdd7 Mon Sep 17 00:00:00 2001 From: Alfie Eagleton <67986414+TheAlfanator@users.noreply.github.com> Date: Sat, 16 Oct 2021 17:16:21 +0100 Subject: Report Writing I implemented the existing bullet pointed intro document into a fuilly written report.tex file, then merged into esoteric_project_report.text under Chapter 1 and Chapter 2 --- report/esoteric_project_report.pdf | Bin 878581 -> 193134 bytes report/esoteric_project_report.tex | 36 +++++++++++++++++++++------------- report/report.tex | 39 +++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 report/report.tex diff --git a/report/esoteric_project_report.pdf b/report/esoteric_project_report.pdf index db4a8c1..67ff856 100644 Binary files a/report/esoteric_project_report.pdf and b/report/esoteric_project_report.pdf differ diff --git a/report/esoteric_project_report.tex b/report/esoteric_project_report.tex index 2f20a7e..8306b94 100644 --- a/report/esoteric_project_report.tex +++ b/report/esoteric_project_report.tex @@ -43,31 +43,41 @@ \begin{abstract} -An abstract is a brief summary (maximum 250 words) of your entire project. It should cover your objectives, your methodology used, how you implemented the methodology for your specific results and what your final results are, your final outcome or deliverable and conclusion. You do not cover literature reviews or background in an abstract nor should you use abbreviations or acronyms. In the remainder of the report the chapter titles are suggestions and can be changed (or you can add more chapters if you wish to do so). This template is designed to help you write a clear report but you are welcome to modify it (at your peril ...). Finally, a guideline in size is approximately 3,500 words (not including abstract, captions and references) but no real limit on figures, tables, etc. +ABSTRACT INCOMPLETE \end{abstract} \chapter{Introduction} \label{chap:intro} +For this project we have decided to create an Esolang interpreter in Java so that we can write code, craft Boolean expressions and calculate Math. We plan to research, design and implement an esoteric language while also understanding fundamental advanced programming concepts. -The introduction should be brief and comprise the following: +\section{Functional Requirements} +After some discussion, we decided that our goals for this project are to create grammar for a language and form a lexical analysis algorithm. After this, we may develop a parser or interpreter so that we can convert our high level code into bytecode which can be read more easily by the JVM. -\section{Project statement} -A (brief) statement including the nature of the project, i.e.\ what you will do, how you will accomplish it and what the final deliverable will be. +\section{Non-functional Requirements} +Our code should be well tested, and be capable of handling edge cases. It should be modular and scalable so that functionality can easily be added without undue difficulty. It would be good if our interpreter could calculate mathematical functions and have good performance with well optimized code. -\section{MoSCoW} +\section{Technology} +We are looking at coding Java in IntelliJ, and potentially using GNU Bison to parse. -Specify the Must-Should-Could-Won't functionality of your software product. -Besides the usual itemised list (or table) you may also add a text clarifying as to why certain items are more important or why certain items will not make it to the final deliverable. A MoSCoW does not need to be complete early on in the project and can be updated well into the project though conversely, it should neither be reversely specified at the end of the project to match the final deliverable! +\section{MoSCoW Analysis} +We thought about what our interpreter may or may not have so that we have a clear understanding of our priorities when coding. We decided that our software \emph{must} read and interpret commands immediately from a command line. The language \emph{must} be Turing complete, and be capable of detecting syntax and runtime errors. It \emph{should} be able to read from file and execute a script. It also \emph{should} be able to optimize source code during runtime. The interpreter \emph{could} be able to implement functions and procedures with return values, and be able to handle memory allocation and disposal. Our program \emph{won't have} a graphical or web-based interface, since it would take up too much development time and is not entirely needed for the scope of this project. It also will not implement object-oriented programming features. \section{Report structure} Breifly describe what you will cover in the remainder of the report, chapter by chapter. -\chapter{Background} +\chapter{Research of Similar Systems} -Depending on the nature of the project, this chapter may cover a literature, resource and/or (software) product review. For a literature review you will consult journal or conference papers outlining methodologies that you may (or may not) use but which are definitely relevant to your particular problem. Resource and/or product information will typcially be substantiated through internet links. -You may use different sections if different subareas are part of your problem statement and/or solution. -Since this chapter covers background resources, you should also update the corresponding bib file referred to in the bottom of this document and here it is called References.bib. -You cite references like this: Taylor et al. \cite{Taylor:2007} investigated non-linear FEA on the GPU. Morton \cite{Morton:1966} developed a file sequencing method in 1966. A website on OpenCL can be found here \cite{Soos:2012}. Etc. +\section{Compilers vs Interpreters} +Within the field of computer programming languages, there are two main types: compiled languages and interpreted languages. Both of these styles have distinct advantages and disadvantages. Compilers and interpreters both convert code written in human readable higher-level languages to instructions that a computer can execute. In the case of compiler, code is converted from high level program code to assembly language then to machine language. This process can be slow, especially when there is a large amount of code to compile, but execution is fast as only the instructions directly executed are required to be kept in memory. In contrast to this, Interpreter directly runs the code given to it, or in other words, an interpreter is a separate program that reads and executes the instructions itself, rather than converting them into the assembly language of that particular architecture being run on. The principal advantage of this is that a computationally expensive compilation process does not have to be run every time, therefore leading to faster startup times. However, this approach carries with it a big disadvantage, namely that because every line has to be interpreted, execution is slower than the equivalent instructions run in a compiled language. + +\section{Programming Languages} +There are a number of prominent interpreted languages in use today, including Python, Matlab, Perl, Ruby and PHP. All of these languages have interpreters that are written in C or C++, which are compiled languages. The interpreters for each language are loaded into memory, along with an instruction that they then interpret. + +\section{Esolangs} +Esolangs are programming languages designed to be jokes or proof of concept languages, rather than those to be used in actual programming tasks. Typically, the reason they are created is for fun rather than any serious desire to solve a particular programming problem, and so most languages aim to be funny, to be as difficult to use as possible or to have few features while still being Turing complete. + +\section{Example - Shakespearian Programming Language} +The Shakespeare Programming Language is esoteric code parodied on extracts from Romeo and Juliet. Here, code is written so it reads like how a script would, such as \texttt{[Enter Juliet]} where \texttt{Juliet} may be a variable name. Other examples include using \texttt{Acts} or \texttt{Scenes} as GOTO statements, where the interpreter can jump to a certain point in the code and read from there. Otherwise, these are ignored similar to the title or character descriptions. Other examples include LOLCODE, Hodor or White Space. This serves the purpose of writing code in a different manner to usual, sometimes for humour. The aim is to replace typical language features so that it can still be read by a compiler or interpreter but also look and read very differently by the user. \chapter{Methodology}\label{MethLab} @@ -116,7 +126,6 @@ The purpose of this section is to just show you how to integrate figures, tables \begin{figure}[htb] %\begin{center} -\includegraphics[width=1.0 \columnwidth]{pelvis_octree.png} \caption{The bony pelvis model with octree based AABBs (Axis Aligned Bounding Boxes).} \label{Pelvis_BVH} %\end{center} @@ -126,7 +135,6 @@ Fig.\ \ref{class} shows a UML class diagram (class, sequence and state diagrams \begin{figure}[htb] %\begin{center} -\includegraphics[width=1.0 \columnwidth]{class.png} \caption{A UML class diagram.} \label{class} %\end{center} diff --git a/report/report.tex b/report/report.tex new file mode 100644 index 0000000..c35bd0e --- /dev/null +++ b/report/report.tex @@ -0,0 +1,39 @@ +\documentclass[12pt]{scrartcl} +\title{Advanced Programming Esoteric Project} +\author{Alfie Eagleton 100274245\\Eden Attenborough 100301654\\Aiden Rushbrooke 100235483\\Chris Sutcliffe 100228212} + +\begin{document} + +\maketitle +\clearpage + +\section{Introduction \& Objectives} +For this project we have decided to create an Esolang interpreter in Java so that we can write code, craft Boolean expressions and calculate Math. We plan to research, design and implement an esoteric language while also understanding fundamental advanced programming concepts. + + +\section{Functional Requirements} +After some discussion, we decided that our goals for this project are to create grammar for a language and form a lexical analysis algorithm. After this, we may develop a parser or interpreter so that we can convert our high level code into bytecode which can be read more easily by the JVM. + +\section{Non-functional Requirements} +Our code should be well tested, and be capable of handling edge cases. It should be modular and scalable so that functionality can easily be added without undue difficulty. It would be good if our interpreter could calculate mathematical functions and have good performance with well optimized code. + +\section{Technology} +We are looking at coding Java in IntelliJ, and potentially using GNU Bison to parse. + +\section{MoSCoW Analysis} +We thought about what our interpreter may or may not have so that we have a clear understanding of our priorities when coding. We decided that our software \emph{must} read and interpret commands immediately from a command line. The language \emph{must} be Turing complete, and be capable of detecting syntax and runtime errors. It \emph{should} be able to read from file and execute a script. It also \emph{should} be able to optimize source code during runtime. The interpreter \emph{could} be able to implement functions and procedures with return values, and be able to handle memory allocation and disposal. Our program \emph{won't have} a graphical or web-based interface, since it would take up too much development time and is not entirely needed for the scope of this project. It also will not implement object-oriented programming features. + +\section{Similar systems and Research} +\subsection{Compilers vs Interpreters} +Within the field of computer programming languages, there are two main types: compiled languages and interpreted languages. Both of these styles have distinct advantages and disadvantages. Compilers and interpreters both convert code written in human readable higher-level languages to instructions that a computer can execute. In the case of compiler, code is converted from high level program code to assembly language then to machine language. This process can be slow, especially when there is a large amount of code to compile, but execution is fast as only the instructions directly executed are required to be kept in memory. In contrast to this, Interpreter directly runs the code given to it, or in other words, an interpreter is a separate program that reads and executes the instructions itself, rather than converting them into the assembly language of that particular architecture being run on. The principal advantage of this is that a computationally expensive compilation process does not have to be run every time, therefore leading to faster startup times. However, this approach carries with it a big disadvantage, namely that because every line has to be interpreted, execution is slower than the equivalent instructions run in a compiled language. + +\subsection{Programming Languages} +There are a number of prominent interpreted languages in use today, including Python, Matlab, Perl, Ruby and PHP. All of these languages have interpreters that are written in C or C++, which are compiled languages. The interpreters for each language are loaded into memory, along with an instruction that they then interpret. + +\subsection{Esolangs} +Esolangs are programming languages designed to be jokes or proof of concept languages, rather than those to be used in actual programming tasks. Typically, the reason they are created is for fun rather than any serious desire to solve a particular programming problem, and so most languages aim to be funny, to be as difficult to use as possible or to have few features while still being Turing complete. + +\subsection{Example - Shakespearian Programming Language} +The Shakespeare Programming Language is esoteric code parodied on extracts from Romeo and Juliet. Here, code is written so it reads like how a script would, such as \texttt{[Enter Juliet]} where \texttt{Juliet} may be a variable name. Other examples include using \texttt{Acts} or \texttt{Scenes} as GOTO statements, where the interpreter can jump to a certain point in the code and read from there. Otherwise, these are ignored similar to the title or character descriptions. Other examples include LOLCODE, Hodor or White Space. This serves the purpose of writing code in a different manner to usual, sometimes for humour. The aim is to replace typical language features so that it can still be read by a compiler or interpreter but also look and read very differently by the user. + +\end{document} \ No newline at end of file -- cgit v1.2.3 From b49bb78db545f0aa6569d8e78e79d4740ca77c4a Mon Sep 17 00:00:00 2001 From: Alfie Eagleton <67986414+TheAlfanator@users.noreply.github.com> Date: Sun, 17 Oct 2021 17:53:14 +0100 Subject: Chapter 3 - FORTRAN Created a grammar table regarding FORTRAN and Java. --- report/esoteric_project_report.pdf | Bin 193134 -> 197284 bytes report/esoteric_project_report.tex | 66 +++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/report/esoteric_project_report.pdf b/report/esoteric_project_report.pdf index 67ff856..58a9978 100644 Binary files a/report/esoteric_project_report.pdf and b/report/esoteric_project_report.pdf differ diff --git a/report/esoteric_project_report.tex b/report/esoteric_project_report.tex index 8306b94..055f752 100644 --- a/report/esoteric_project_report.tex +++ b/report/esoteric_project_report.tex @@ -79,6 +79,72 @@ Esolangs are programming languages designed to be jokes or proof of concept lang \section{Example - Shakespearian Programming Language} The Shakespeare Programming Language is esoteric code parodied on extracts from Romeo and Juliet. Here, code is written so it reads like how a script would, such as \texttt{[Enter Juliet]} where \texttt{Juliet} may be a variable name. Other examples include using \texttt{Acts} or \texttt{Scenes} as GOTO statements, where the interpreter can jump to a certain point in the code and read from there. Otherwise, these are ignored similar to the title or character descriptions. Other examples include LOLCODE, Hodor or White Space. This serves the purpose of writing code in a different manner to usual, sometimes for humour. The aim is to replace typical language features so that it can still be read by a compiler or interpreter but also look and read very differently by the user. +\chapter{Grammar - FORTRAN} + +\section {Why we chose FORTRAN} + +asdf + +\begin{table}[h!] + \begin{center} + + \begin{tabular}{|l|r|} + \hline + \textbf{Token} & \textbf{Replaces}\\ + \hline + ! & \slash\slash \\ + \hline + PROGRAM x & public class x \{ \\ + \hline + END PROGRAM & \} \\ + \hline + INTEGER & int \\ + \hline + LOGICAL & boolean \\ + \hline + .FALSE. & false \\ + \hline + .TRUE. & true \\ + \hline + CHARACTER(LEN=x) & String \\ + \hline + :: & = \\ + \hline + IF (x) THEN & if(x) \{ \\ + \hline + ELSE & else \\ + \hline + END IF & \} \\ + \hline + SELECT CASE (x) & switch(x) \{ \\ + \hline + CASE (x) & case x: \\ + \hline + CASE DEFAULT & default: \\ + \hline + END SELECT & \} \\ + \hline + x & x; \\ + \hline + DO x = y, z & for(x = y, x < z; x++) \{ \\ + \hline + END DO & \} \\ + \hline + PRINT *, x & System.out.println(x); \\ + \hline + SUBROUTINE x & static void x() \{ \\ + \hline + END SUBROUTINE & \} \\ + \hline + CALL x & x(); \\ + \hline + + \end{tabular} + \label{tab:table1} + \caption{Grammar table for Fortran} + \end{center} +\end{table} + \chapter{Methodology}\label{MethLab} Describe here various methods that will be used in your project. Use different sections for distinctly different subjects and use subsections for specific details on the same subject. Only use subsubsections or paragraphs (which are not numbered) if you believe this is really necessary. Since implementation will happen in sprints, this section may need several updates with parts being added and deleted across the project. -- cgit v1.2.3 From 8d0f7e7ac306e6c49cfd5735417b0a8b78c98f34 Mon Sep 17 00:00:00 2001 From: chris-sutcliffe Date: Sun, 17 Oct 2021 21:26:07 +0100 Subject: change report structure slightly, add subheadings --- report/esoteric_project_report.tex | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/report/esoteric_project_report.tex b/report/esoteric_project_report.tex index 8306b94..d1326b7 100644 --- a/report/esoteric_project_report.tex +++ b/report/esoteric_project_report.tex @@ -68,12 +68,16 @@ Breifly describe what you will cover in the remainder of the report, chapter by \chapter{Research of Similar Systems} \section{Compilers vs Interpreters} -Within the field of computer programming languages, there are two main types: compiled languages and interpreted languages. Both of these styles have distinct advantages and disadvantages. Compilers and interpreters both convert code written in human readable higher-level languages to instructions that a computer can execute. In the case of compiler, code is converted from high level program code to assembly language then to machine language. This process can be slow, especially when there is a large amount of code to compile, but execution is fast as only the instructions directly executed are required to be kept in memory. In contrast to this, Interpreter directly runs the code given to it, or in other words, an interpreter is a separate program that reads and executes the instructions itself, rather than converting them into the assembly language of that particular architecture being run on. The principal advantage of this is that a computationally expensive compilation process does not have to be run every time, therefore leading to faster startup times. However, this approach carries with it a big disadvantage, namely that because every line has to be interpreted, execution is slower than the equivalent instructions run in a compiled language. +Within the field of computer programming languages, there are two main types: compiled languages and interpreted languages. Both of these styles have distinct advantages and disadvantages. Compilers and interpreters both convert code written in human readable higher-level languages to instructions that a computer can execute. -\section{Programming Languages} +In the case of compiler, code is converted from high level program code to assembly language then to machine language. This process can be slow, especially when there is a large amount of code to compile, but execution is fast as only the instructions directly executed are required to be kept in memory. + +In contrast to this, Interpreter directly runs the code given to it, or in other words, an interpreter is a separate program that reads and executes the instructions itself, rather than converting them into the assembly language of that particular architecture being run on. The principal advantage of this is that a computationally expensive compilation process does not have to be run every time, therefore leading to faster startup times. However, this approach carries with it a big disadvantage, namely that because every line has to be interpreted, execution is slower than the equivalent instructions run in a compiled language. + +\section{Interpreted Programming Languages} There are a number of prominent interpreted languages in use today, including Python, Matlab, Perl, Ruby and PHP. All of these languages have interpreters that are written in C or C++, which are compiled languages. The interpreters for each language are loaded into memory, along with an instruction that they then interpret. -\section{Esolangs} +\section{Esoteric Languages (Esolangs)} Esolangs are programming languages designed to be jokes or proof of concept languages, rather than those to be used in actual programming tasks. Typically, the reason they are created is for fun rather than any serious desire to solve a particular programming problem, and so most languages aim to be funny, to be as difficult to use as possible or to have few features while still being Turing complete. \section{Example - Shakespearian Programming Language} -- cgit v1.2.3 From 3c3706a8957f27d7bcb553eff6ded1c6dc76fa24 Mon Sep 17 00:00:00 2001 From: chris-sutcliffe Date: Mon, 18 Oct 2021 15:43:54 +0100 Subject: add some notes on grammar and start lexer section --- report/esoteric_project_report.pdf | Bin 197284 -> 189988 bytes report/esoteric_project_report.tex | 61 ++++++++++++++++++++++++++++++++++++- report/report.pdf | Bin 0 -> 67012 bytes 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 report/report.pdf diff --git a/report/esoteric_project_report.pdf b/report/esoteric_project_report.pdf index 58a9978..b241efe 100644 Binary files a/report/esoteric_project_report.pdf and b/report/esoteric_project_report.pdf differ diff --git a/report/esoteric_project_report.tex b/report/esoteric_project_report.tex index 25491d5..788226a 100644 --- a/report/esoteric_project_report.tex +++ b/report/esoteric_project_report.tex @@ -83,7 +83,66 @@ Esolangs are programming languages designed to be jokes or proof of concept lang \section{Example - Shakespearian Programming Language} The Shakespeare Programming Language is esoteric code parodied on extracts from Romeo and Juliet. Here, code is written so it reads like how a script would, such as \texttt{[Enter Juliet]} where \texttt{Juliet} may be a variable name. Other examples include using \texttt{Acts} or \texttt{Scenes} as GOTO statements, where the interpreter can jump to a certain point in the code and read from there. Otherwise, these are ignored similar to the title or character descriptions. Other examples include LOLCODE, Hodor or White Space. This serves the purpose of writing code in a different manner to usual, sometimes for humour. The aim is to replace typical language features so that it can still be read by a compiler or interpreter but also look and read very differently by the user. -\chapter{Grammar - FORTRAN} +\chapter{The Structure of our Programming Language} +\section{The Lexar (Lexical Analysis)} +In the field of linguistics or computer programming language design, lexical analysis is the process of converting a sequence of characters (such as a computer program) into a sequence of tokens. +This process is also known as tokenisation, particularly in the field of natural language processing (NLP). +When designing a programming language, the task of lexical analysis or tokenisation is performed by a lexer. +The actual matching of tokens is often performed using regular expressions, defined in the design stage in order to reliably match all tokens in the language. + + +\chapter{Grammar} + + +\section{Introduction to Language Grammar} +\begin{verbatim} + +Work in progress currently + +\end{verbatim} +Context free grammars – something = something else + +Context free because there is no rule or context about where this grammar belongs, only where it goes + +Rewrite rules: +S $\rightarrow$ DET N +Were first invented by Panini %Pāṇini + who worked on Sanscrit grammar rules + +Port Royal Grammer by Antoine Arnauld and Claude Lancelot in 1660 who worked at Port-Royal-des-Champs + +then Ferdinand de Saussure (19th century) + +then Chomsky with Chomsky hierarchy. + + +BNF form (Backus Naur form) is a meta language for grammars +Named after the people who invented it simultaneously +example: +\begin{verbatim} ::= ? +\end{verbatim} +This means a program consists of a sequence of allowable grammars followed by question mark +Can be read as “program consists of a sequence of things followed by question mark” + + +Grammar consists of a series of rewrite rules +Grammar is a quadruple. It is a set of: +\begin{itemize} + \item Terminal symbols + \item Non terminal symbols + \item Set of rules + \item Start symbol (one of the non-terminal symbols) +\end{itemize} + + +Any regular grammar can be recognised by regular expressions (refer to regular grammar in Chomksy hierarchy) + +After Chomsky came Backus and Naur – BNF + +Niklaus Wirth – Pascal language + +Dijkstra – programming without goto (gotoless programming) + \section {Why we chose FORTRAN} diff --git a/report/report.pdf b/report/report.pdf new file mode 100644 index 0000000..33a6960 Binary files /dev/null and b/report/report.pdf differ -- cgit v1.2.3 From e09b0bb865bbb0087c46b4acd90b759f14dfa824 Mon Sep 17 00:00:00 2001 From: jwansek Date: Mon, 18 Oct 2021 16:40:56 +0100 Subject: added sableCC calculator --- .gitignore | 4 + code/simpleSableCCCalulator/README.md | 20 ++++ code/simpleSableCCCalulator/examples/maths.txt | 1 + code/simpleSableCCCalulator/examples/maths2.txt | 1 + code/simpleSableCCCalulator/examples/maths3.txt | 1 + .../sableCCCalculator.grammar | 35 ++++++ .../sableCCCalculator/Compiler.java | 27 +++++ .../sableCCCalculator/ProgramStack.java | 28 +++++ .../sableCCCalculator/Translation.java | 132 +++++++++++++++++++++ 9 files changed, 249 insertions(+) create mode 100644 code/simpleSableCCCalulator/README.md create mode 100644 code/simpleSableCCCalulator/examples/maths.txt create mode 100644 code/simpleSableCCCalulator/examples/maths2.txt create mode 100644 code/simpleSableCCCalulator/examples/maths3.txt create mode 100644 code/simpleSableCCCalulator/sableCCCalculator.grammar create mode 100644 code/simpleSableCCCalulator/sableCCCalculator/Compiler.java create mode 100644 code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java create mode 100644 code/simpleSableCCCalulator/sableCCCalculator/Translation.java diff --git a/.gitignore b/.gitignore index 3f7cb11..e44e557 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ *.class +code/simpleSableCCCalulator/sableCCCalculator/analysis/ +code/simpleSableCCCalulator/sableCCCalculator/lexer/ +code/simpleSableCCCalulator/sableCCCalculator/node/ +code/simpleSableCCCalulator/sableCCCalculator/parser/ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 diff --git a/code/simpleSableCCCalulator/README.md b/code/simpleSableCCCalulator/README.md new file mode 100644 index 0000000..4c75421 --- /dev/null +++ b/code/simpleSableCCCalulator/README.md @@ -0,0 +1,20 @@ +# simpleSableCCCalculator + +sableCC is a too used to parse .grammar files (containing a BNF, and lexer information) +into a lexer and parser. We can do a depth first traversal of the produced abstract syntax tree +to parse in the correct order. This is in the file `Translation.java`. + +You produce a lexer and parser by running the sablecc .jar file you can download [here](http://downloads.sourceforge.net/sablecc/sablecc-3.7.zip). Then run it with the first argument as the grammar file: + +`java -jar sablecc-3.7/lib/sablecc.jar sableCCCalculator.grammar` + +(changing the paths as appropriate). The produced java files are not included in git since they're unnessicary. We compile the compiler, program stack and translator: + +`javac sableCCCalculator/*.java` + +Then we can run the program. For now it only works by reading files. There are some example maths questions in the examples folder: + +`java sableCCCalculator.Compiler examples/maths.txt` + + + diff --git a/code/simpleSableCCCalulator/examples/maths.txt b/code/simpleSableCCCalulator/examples/maths.txt new file mode 100644 index 0000000..f3b3bd9 --- /dev/null +++ b/code/simpleSableCCCalulator/examples/maths.txt @@ -0,0 +1 @@ +(36/2 + 45) * 3 \ No newline at end of file diff --git a/code/simpleSableCCCalulator/examples/maths2.txt b/code/simpleSableCCCalulator/examples/maths2.txt new file mode 100644 index 0000000..1f1d63e --- /dev/null +++ b/code/simpleSableCCCalulator/examples/maths2.txt @@ -0,0 +1 @@ +sin(45 * 3) / 3 \ No newline at end of file diff --git a/code/simpleSableCCCalulator/examples/maths3.txt b/code/simpleSableCCCalulator/examples/maths3.txt new file mode 100644 index 0000000..e092af1 --- /dev/null +++ b/code/simpleSableCCCalulator/examples/maths3.txt @@ -0,0 +1 @@ +3-1+2 \ No newline at end of file diff --git a/code/simpleSableCCCalulator/sableCCCalculator.grammar b/code/simpleSableCCCalulator/sableCCCalculator.grammar new file mode 100644 index 0000000..426fac1 --- /dev/null +++ b/code/simpleSableCCCalulator/sableCCCalculator.grammar @@ -0,0 +1,35 @@ +Package sableCCCalculator; +Helpers + digit = ['0' .. '9']; +Tokens + number = digit+; + double = ((digit)+ '.' (digit)*) | ((digit)* '.' (digit)+); + plus = '+'; + minus = '-'; + mult = '*'; + div = '/'; + mod = '%'; + l_par = '('; + r_par = ')'; + sin = 'sin'; + blank = (' ' | 13 | 10)+; +Ignored Tokens + blank; +Productions + expr = + {factor} factor | + {plus} expr plus factor | + {minus} expr minus factor + ; + factor = + {term} term | + {mult} factor mult term | + {div} factor div term | + {mod} factor mod term + ; + term = + {number} number | + {double} double | + {expr} l_par expr r_par | + {sine} sin l_par expr r_par + ; \ No newline at end of file diff --git a/code/simpleSableCCCalulator/sableCCCalculator/Compiler.java b/code/simpleSableCCCalulator/sableCCCalculator/Compiler.java new file mode 100644 index 0000000..7430cfe --- /dev/null +++ b/code/simpleSableCCCalulator/sableCCCalculator/Compiler.java @@ -0,0 +1,27 @@ +package sableCCCalculator; +import sableCCCalculator.parser.*; +import sableCCCalculator.lexer.*; +import sableCCCalculator.node.*; +import java.io.*; + +public class Compiler +{ + public static void main(String[] args) + { + try + { + System.out.println("Using source file: " + args[0]); + // Create a Parser instance. + Parser p = new Parser(new Lexer(new PushbackReader(new InputStreamReader(new FileInputStream(args[0])), 1024))); + // Parse the input. + Start tree = p.parse(); + // Apply the translation. + tree.apply(new Translation()); + System.out.println(""); + } + catch(Exception e) + { + System.out.println(e.getMessage()); + } + } +} \ No newline at end of file diff --git a/code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java b/code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java new file mode 100644 index 0000000..1875e57 --- /dev/null +++ b/code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java @@ -0,0 +1,28 @@ +package sableCCCalculator; +import sableCCCalculator.node.*; +import java.util.Stack; + +public class ProgramStack extends Stack { + + public String toString() { + String out = "Stack is now: ["; + for (int i = 0; i < this.size(); i++) { + String theStr = this.elementAt(i).toString(); + out += String.format("%s, ", theStr.substring(0, theStr.length() - 1)); + } + return out.substring(0, out.length() - 2) + "]"; + } + + public static void main(String[] args) { + ProgramStack myStack = new ProgramStack<>(); + myStack.add(new TNumber("2")); + myStack.add(new TNumber("4")); + myStack.add(new TNumber("6")); + myStack.add(new TNumber("0")); + myStack.add(new TNumber("1")); + myStack.add(new TDouble("24601.10642")); + + System.out.println(myStack.pop().getText()); + System.out.println(myStack); + } +} diff --git a/code/simpleSableCCCalulator/sableCCCalculator/Translation.java b/code/simpleSableCCCalulator/sableCCCalculator/Translation.java new file mode 100644 index 0000000..d8fd74d --- /dev/null +++ b/code/simpleSableCCCalulator/sableCCCalculator/Translation.java @@ -0,0 +1,132 @@ +package sableCCCalculator; +import sableCCCalculator.analysis.*; +import sableCCCalculator.node.*; + +class Translation extends DepthFirstAdapter +{ + private ProgramStack programStack = new ProgramStack<>(); + + public void caseTNumber(TNumber node) + { + System.out.println("Pushing " + Integer.parseInt(node.getText()) + " to stack"); + programStack.push(node); + System.out.println(programStack); + } + + public void caseTDouble(TDouble node) + { + System.out.println("Pushing a double: " + Double.parseDouble(node.getText())); + programStack.push(node); + System.out.println(programStack); + } + + public void outASineTerm(ASineTerm node) + { + Double num = Double.parseDouble(programStack.pop().getText()); + System.out.println("Popped " + num); + Double out = Math.sin(Math.toRadians(num)); + programStack.push(new TDouble(String.format("%f", out))); + System.out.println("Pushed sin(" + num + ") = " + out + " to stack"); + System.out.println(programStack); + } + + public void outAPlusExpr(APlusExpr node) + { + Double num2 = Double.parseDouble(programStack.pop().getText()); + Double num1 = Double.parseDouble(programStack.pop().getText()); + System.out.println("Popped " + num1 + " and " + num2 + " from stack"); + Double out = num1 + num2; + if ((out % 1) == 0) + { + // the output is an integer, change types to save memory + programStack.push(new TNumber(String.format("%d", out.intValue()))); + } + else + { + programStack.push(new TDouble(String.format("%f", out))); + } + + System.out.println("Pushed " + num1 + "+" + num2 + "=" + out + " to stack"); + System.out.println(programStack); + } + + public void outAMinusExpr(AMinusExpr node) + { + Double num2 = Double.parseDouble(programStack.pop().getText()); + Double num1 = Double.parseDouble(programStack.pop().getText()); + System.out.println("Popped " + num1 + " and " + num2 + " from stack"); + Double out = num1 - num2; + if ((out % 1) == 0) + { + // the output is an integer, change types to save memory + programStack.push(new TNumber(String.format("%d", out.intValue()))); + } + else + { + programStack.push(new TDouble(String.format("%f", out))); + } + + System.out.println("Pushed " + num1 + "-" + num2 + "=" + out + " to stack"); + System.out.println(programStack); + } + + public void outAMultFactor(AMultFactor node) + { + Double num2 = Double.parseDouble(programStack.pop().getText()); + Double num1 = Double.parseDouble(programStack.pop().getText()); + System.out.println("Popped " + num1 + " and " + num2 + " from stack"); + Double out = num1 * num2; + if ((out % 1) == 0) + { + // the output is an integer, change types to save memory + programStack.push(new TNumber(String.format("%d", out.intValue()))); + } + else + { + programStack.push(new TDouble(String.format("%f", out))); + } + + System.out.println("Pushed " + num1 + "*" + num2 + "=" + out + " to stack"); + System.out.println(programStack); + } + + public void outADivFactor(ADivFactor node) + { + Double num2 = Double.parseDouble(programStack.pop().getText()); + Double num1 = Double.parseDouble(programStack.pop().getText()); + System.out.println("Popped " + num1 + " and " + num2 + " from stack"); + Double out = num1 / num2; + if ((out % 1) == 0) + { + // the output is an integer, change types to save memory + programStack.push(new TNumber(String.format("%d", out.intValue()))); + } + else + { + programStack.push(new TDouble(String.format("%f", out))); + } + + System.out.println("Pushed " + num1 + "/" + num2 + "=" + out + " to stack"); + System.out.println(programStack); + } + + public void outAModFactor(AModFactor node) + { + Double num2 = Double.parseDouble(programStack.pop().getText()); + Double num1 = Double.parseDouble(programStack.pop().getText()); + System.out.println("Popped " + num1 + " and " + num2 + " from stack"); + Double out = num1 % num2; + if ((out % 1) == 0) + { + // the output is an integer, change types to save memory + programStack.push(new TNumber(String.format("%d", out.intValue()))); + } + else + { + programStack.push(new TDouble(String.format("%f", out))); + } + + System.out.println("Pushed " + num1 + "%" + num2 + "=" + out + " to stack"); + System.out.println(programStack); + } +} -- cgit v1.2.3 From 8f50e4d189bad9dbd180fd945881950769c3a989 Mon Sep 17 00:00:00 2001 From: jwansek Date: Sun, 24 Oct 2021 14:07:29 +0100 Subject: added the start of a type system --- code/simpleSableCCCalulator/Makefile | 8 ++ code/simpleSableCCCalulator/examples/maths.txt | 2 +- code/simpleSableCCCalulator/examples/maths4.txt | 1 + .../sableCCCalculator/ProgramStack.java | 23 +++-- .../sableCCCalculator/Translation.java | 114 +++++++-------------- .../sableCCCalculator/types/Decimal.java | 57 +++++++++++ .../sableCCCalculator/types/Int.java | 60 +++++++++++ .../sableCCCalculator/types/Type.java | 22 ++++ 8 files changed, 196 insertions(+), 91 deletions(-) create mode 100644 code/simpleSableCCCalulator/Makefile create mode 100644 code/simpleSableCCCalulator/examples/maths4.txt create mode 100644 code/simpleSableCCCalulator/sableCCCalculator/types/Decimal.java create mode 100644 code/simpleSableCCCalulator/sableCCCalculator/types/Int.java create mode 100644 code/simpleSableCCCalulator/sableCCCalculator/types/Type.java diff --git a/code/simpleSableCCCalulator/Makefile b/code/simpleSableCCCalulator/Makefile new file mode 100644 index 0000000..7c6962b --- /dev/null +++ b/code/simpleSableCCCalulator/Makefile @@ -0,0 +1,8 @@ +all: + javac sableCCCalculator/*.java + javac sableCCCalculator/types/*.java + + +clean: + rm -vf sableCCCalculator/*.class + rm -vf sableCCCalculator/types/*class diff --git a/code/simpleSableCCCalulator/examples/maths.txt b/code/simpleSableCCCalulator/examples/maths.txt index f3b3bd9..36726f5 100644 --- a/code/simpleSableCCCalulator/examples/maths.txt +++ b/code/simpleSableCCCalulator/examples/maths.txt @@ -1 +1 @@ -(36/2 + 45) * 3 \ No newline at end of file +(36/2 + 45.2) * 3 \ No newline at end of file diff --git a/code/simpleSableCCCalulator/examples/maths4.txt b/code/simpleSableCCCalulator/examples/maths4.txt new file mode 100644 index 0000000..5b3e67d --- /dev/null +++ b/code/simpleSableCCCalulator/examples/maths4.txt @@ -0,0 +1 @@ +2 + 3.1 diff --git a/code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java b/code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java index 1875e57..c1046ee 100644 --- a/code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java +++ b/code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java @@ -1,26 +1,27 @@ package sableCCCalculator; -import sableCCCalculator.node.*; +import sableCCCalculator.types.*; import java.util.Stack; -public class ProgramStack extends Stack { +public class ProgramStack extends Stack { public String toString() { String out = "Stack is now: ["; for (int i = 0; i < this.size(); i++) { - String theStr = this.elementAt(i).toString(); - out += String.format("%s, ", theStr.substring(0, theStr.length() - 1)); + // String theStr = this.elementAt(i).toString(); + // out += String.format("%s, ", theStr.substring(0, theStr.length() - 1)); + out += String.format("%s, ", this.elementAt(i).toString()); } return out.substring(0, out.length() - 2) + "]"; } public static void main(String[] args) { - ProgramStack myStack = new ProgramStack<>(); - myStack.add(new TNumber("2")); - myStack.add(new TNumber("4")); - myStack.add(new TNumber("6")); - myStack.add(new TNumber("0")); - myStack.add(new TNumber("1")); - myStack.add(new TDouble("24601.10642")); + ProgramStack myStack = new ProgramStack<>(); + myStack.add(new Int(2)); + myStack.add(new Int(4)); + myStack.add(new Int(6)); + myStack.add(new Int(0)); + myStack.add(new Int(1)); + myStack.add(new Decimal(24601.10642)); System.out.println(myStack.pop().getText()); System.out.println(myStack); diff --git a/code/simpleSableCCCalulator/sableCCCalculator/Translation.java b/code/simpleSableCCCalulator/sableCCCalculator/Translation.java index d8fd74d..a673edb 100644 --- a/code/simpleSableCCCalulator/sableCCCalculator/Translation.java +++ b/code/simpleSableCCCalulator/sableCCCalculator/Translation.java @@ -1,22 +1,23 @@ package sableCCCalculator; import sableCCCalculator.analysis.*; +import sableCCCalculator.types.*; import sableCCCalculator.node.*; class Translation extends DepthFirstAdapter { - private ProgramStack programStack = new ProgramStack<>(); + private ProgramStack programStack = new ProgramStack<>(); public void caseTNumber(TNumber node) { System.out.println("Pushing " + Integer.parseInt(node.getText()) + " to stack"); - programStack.push(node); + programStack.push(new Int(node.getText())); System.out.println(programStack); } public void caseTDouble(TDouble node) { System.out.println("Pushing a double: " + Double.parseDouble(node.getText())); - programStack.push(node); + programStack.push(new Decimal(node.getText())); System.out.println(programStack); } @@ -25,108 +26,63 @@ class Translation extends DepthFirstAdapter Double num = Double.parseDouble(programStack.pop().getText()); System.out.println("Popped " + num); Double out = Math.sin(Math.toRadians(num)); - programStack.push(new TDouble(String.format("%f", out))); + programStack.push(new Decimal(out)); System.out.println("Pushed sin(" + num + ") = " + out + " to stack"); System.out.println(programStack); } public void outAPlusExpr(APlusExpr node) { - Double num2 = Double.parseDouble(programStack.pop().getText()); - Double num1 = Double.parseDouble(programStack.pop().getText()); - System.out.println("Popped " + num1 + " and " + num2 + " from stack"); - Double out = num1 + num2; - if ((out % 1) == 0) - { - // the output is an integer, change types to save memory - programStack.push(new TNumber(String.format("%d", out.intValue()))); - } - else - { - programStack.push(new TDouble(String.format("%f", out))); - } - - System.out.println("Pushed " + num1 + "+" + num2 + "=" + out + " to stack"); + Type op2 = programStack.pop(); + Type op1 = programStack.pop(); + System.out.println("Popped " + op1 + " and " + op2 + " from stack"); + Type out = op1.add(op2); + programStack.push(out); + System.out.println("Pushed " + op1 + "+" + op2 + "=" + out + " to stack"); System.out.println(programStack); } public void outAMinusExpr(AMinusExpr node) { - Double num2 = Double.parseDouble(programStack.pop().getText()); - Double num1 = Double.parseDouble(programStack.pop().getText()); - System.out.println("Popped " + num1 + " and " + num2 + " from stack"); - Double out = num1 - num2; - if ((out % 1) == 0) - { - // the output is an integer, change types to save memory - programStack.push(new TNumber(String.format("%d", out.intValue()))); - } - else - { - programStack.push(new TDouble(String.format("%f", out))); - } - - System.out.println("Pushed " + num1 + "-" + num2 + "=" + out + " to stack"); + Type op2 = programStack.pop(); + Type op1 = programStack.pop(); + System.out.println("Popped " + op1 + " and " + op2 + " from stack"); + Type out = op1.sub(op2); + programStack.push(out); + System.out.println("Pushed " + op1 + "-" + op2 + "=" + out + " to stack"); System.out.println(programStack); } public void outAMultFactor(AMultFactor node) { - Double num2 = Double.parseDouble(programStack.pop().getText()); - Double num1 = Double.parseDouble(programStack.pop().getText()); - System.out.println("Popped " + num1 + " and " + num2 + " from stack"); - Double out = num1 * num2; - if ((out % 1) == 0) - { - // the output is an integer, change types to save memory - programStack.push(new TNumber(String.format("%d", out.intValue()))); - } - else - { - programStack.push(new TDouble(String.format("%f", out))); - } - - System.out.println("Pushed " + num1 + "*" + num2 + "=" + out + " to stack"); + Type op2 = programStack.pop(); + Type op1 = programStack.pop(); + System.out.println("Popped " + op1 + " and " + op2 + " from stack"); + Type out = op1.mult(op2); + programStack.push(out); + System.out.println("Pushed " + op1 + "*" + op2 + "=" + out + " to stack"); System.out.println(programStack); } public void outADivFactor(ADivFactor node) { - Double num2 = Double.parseDouble(programStack.pop().getText()); - Double num1 = Double.parseDouble(programStack.pop().getText()); - System.out.println("Popped " + num1 + " and " + num2 + " from stack"); - Double out = num1 / num2; - if ((out % 1) == 0) - { - // the output is an integer, change types to save memory - programStack.push(new TNumber(String.format("%d", out.intValue()))); - } - else - { - programStack.push(new TDouble(String.format("%f", out))); - } - - System.out.println("Pushed " + num1 + "/" + num2 + "=" + out + " to stack"); + Type op2 = programStack.pop(); + Type op1 = programStack.pop(); + System.out.println("Popped " + op1 + " and " + op2 + " from stack"); + Type out = op1.div(op2); + programStack.push(out); + System.out.println("Pushed " + op1 + "/" + op2 + "=" + out + " to stack"); System.out.println(programStack); } public void outAModFactor(AModFactor node) { - Double num2 = Double.parseDouble(programStack.pop().getText()); - Double num1 = Double.parseDouble(programStack.pop().getText()); - System.out.println("Popped " + num1 + " and " + num2 + " from stack"); - Double out = num1 % num2; - if ((out % 1) == 0) - { - // the output is an integer, change types to save memory - programStack.push(new TNumber(String.format("%d", out.intValue()))); - } - else - { - programStack.push(new TDouble(String.format("%f", out))); - } - - System.out.println("Pushed " + num1 + "%" + num2 + "=" + out + " to stack"); + Type op2 = programStack.pop(); + Type op1 = programStack.pop(); + System.out.println("Popped " + op1 + " and " + op2 + " from stack"); + Type out = op1.mod(op2); + programStack.push(out); + System.out.println("Pushed " + op1 + "%" + op2 + "=" + out + " to stack"); System.out.println(programStack); } } diff --git a/code/simpleSableCCCalulator/sableCCCalculator/types/Decimal.java b/code/simpleSableCCCalulator/sableCCCalculator/types/Decimal.java new file mode 100644 index 0000000..5836ff1 --- /dev/null +++ b/code/simpleSableCCCalulator/sableCCCalculator/types/Decimal.java @@ -0,0 +1,57 @@ +package sableCCCalculator.types; + +public class Decimal extends Type { + + public Decimal(Double toDecimal) { + javaObject = (Double)toDecimal; + } + + public Decimal(String toDecimal) { + javaObject = (Double)Double.parseDouble(toDecimal); + } + + public Decimal add(Type toAdd) { + if (toAdd.getClass().getSimpleName().equals("Decimal")) { + return new Decimal((Double)this.javaObject + (double)toAdd.javaObject); + } else { + return new Decimal((Double)this.javaObject + Double.parseDouble(String.format("%d", (int)toAdd.javaObject))); + } + } + + public Decimal sub(Type toAdd) { + if (toAdd.getClass().getSimpleName().equals("Decimal")) { + return new Decimal((Double)this.javaObject - (double)toAdd.javaObject); + } else { + return new Decimal((Double)this.javaObject - Double.parseDouble(String.format("%d", (int)toAdd.javaObject))); + } + } + + public Decimal mult(Type toAdd) { + if (toAdd.getClass().getSimpleName().equals("Decimal")) { + return new Decimal((Double)this.javaObject * (double)toAdd.javaObject); + } else { + return new Decimal((Double)this.javaObject * Double.parseDouble(String.format("%d", (int)toAdd.javaObject))); + } + } + + public Decimal div(Type toAdd) { + if (toAdd.getClass().getSimpleName().equals("Decimal")) { + return new Decimal((Double)this.javaObject / (double)toAdd.javaObject); + } else { + return new Decimal((Double)this.javaObject / Double.parseDouble(String.format("%d", (int)toAdd.javaObject))); + } + } + + public Decimal mod(Type toAdd) { + if (toAdd.getClass().getSimpleName().equals("Decimal")) { + return new Decimal((Double)this.javaObject % (double)toAdd.javaObject); + } else { + return new Decimal((Double)this.javaObject % Double.parseDouble(String.format("%d", (int)toAdd.javaObject))); + } + } + + public static void main(String[] args) { + Decimal aDec = new Decimal(3.1); + System.out.println(aDec.sub(new Int(2))); + } +} diff --git a/code/simpleSableCCCalulator/sableCCCalculator/types/Int.java b/code/simpleSableCCCalulator/sableCCCalculator/types/Int.java new file mode 100644 index 0000000..1ccd20e --- /dev/null +++ b/code/simpleSableCCCalulator/sableCCCalculator/types/Int.java @@ -0,0 +1,60 @@ +package sableCCCalculator.types; + +public class Int extends Type { + + public Int(int toInt) { + javaObject = (Integer)toInt; + } + + public Int(String toInt) { + javaObject = (Integer)Integer.parseInt(toInt); + } + + public Type add(Type toAdd) { + if (toAdd.getClass().getSimpleName().equals("Int")) { + return new Int((int)this.javaObject + (int)toAdd.javaObject); + } else { + return new Decimal(Double.parseDouble(String.format("%d", (int)this.javaObject)) + (Double)toAdd.javaObject); + } + } + + public Type sub(Type toAdd) { + if (toAdd.getClass().getSimpleName().equals("Int")) { + return new Int((int)this.javaObject - (int)toAdd.javaObject); + } else { + return new Decimal(Double.parseDouble(String.format("%d", (int)this.javaObject)) - (Double)toAdd.javaObject); + } + } + + public Type mult(Type toAdd) { + if (toAdd.getClass().getSimpleName().equals("Int")) { + return new Int((int)this.javaObject * (int)toAdd.javaObject); + } else { + return new Decimal(Double.parseDouble(String.format("%d", (int)this.javaObject)) * (Double)toAdd.javaObject); + } + } + + public Type div(Type toAdd) { + if (toAdd.getClass().getSimpleName().equals("Int")) { + return new Int((int)this.javaObject / (int)toAdd.javaObject); + } else { + return new Decimal(Double.parseDouble(String.format("%d", (int)this.javaObject)) / (Double)toAdd.javaObject); + } + } + + public Type mod(Type toAdd) { + if (toAdd.getClass().getSimpleName().equals("Int")) { + return new Int((int)this.javaObject % (int)toAdd.javaObject); + } else { + return new Decimal(Double.parseDouble(String.format("%d", (int)this.javaObject)) % (Double)toAdd.javaObject); + } + } + + public static void main(String[] args) { + Int int1 = new Int(3); + System.out.println(int1.add(new Int(4))); + + Int int2 = new Int(3); + System.out.println(int2.mult(new Decimal(2.2))); + } +} diff --git a/code/simpleSableCCCalulator/sableCCCalculator/types/Type.java b/code/simpleSableCCCalulator/sableCCCalculator/types/Type.java new file mode 100644 index 0000000..359f2b8 --- /dev/null +++ b/code/simpleSableCCCalulator/sableCCCalculator/types/Type.java @@ -0,0 +1,22 @@ +package sableCCCalculator.types; + +// not happy with the amount of polymorphism +// using generics would be better but idk how that'd work in this context... +public abstract class Type { + + protected Object javaObject; + + public abstract Type add(Type toAdd); + public abstract Type sub(Type toSub); + public abstract Type mult(Type toMult); + public abstract Type div(Type toDiv); + public abstract Type mod(Type toMod); + + public String toString() { + return javaObject.toString(); + } + + public String getText() { + return this.toString(); + } +} \ No newline at end of file -- cgit v1.2.3 From 814c115d8accedc07e42d218bfdab639148fa836 Mon Sep 17 00:00:00 2001 From: jwansek Date: Sun, 24 Oct 2021 15:59:49 +0100 Subject: started work on the symbol table, preparing for variables --- .../sableCCCalculator/SymbolTable.java | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 code/simpleSableCCCalulator/sableCCCalculator/SymbolTable.java diff --git a/code/simpleSableCCCalulator/sableCCCalculator/SymbolTable.java b/code/simpleSableCCCalulator/sableCCCalculator/SymbolTable.java new file mode 100644 index 0000000..435e48d --- /dev/null +++ b/code/simpleSableCCCalulator/sableCCCalculator/SymbolTable.java @@ -0,0 +1,48 @@ +package sableCCCalculator; +import java.util.HashMap; +import sableCCCalculator.types.*; + +public class SymbolTable { + + public interface SymbolTableIndex {} + + public abstract class Name implements SymbolTableIndex { + protected String name; + + String getName() { + return this.name; + } + } + + public class Constant implements SymbolTableIndex { + int index; + + public Constant(int index) { + this.index = index; + } + } + + public class Variable extends Name { + public Variable(String name) { + this.name = name; + } + } + + private HashMap theSymbolTable = new HashMap<>(); + + public SymbolTableIndex addConstant(Type item) { + SymbolTableIndex index = new Constant(item.hashCode()); + theSymbolTable.put(index, item); + return index; + } + + public SymbolTableIndex addVariable(Type item, String name) { + SymbolTableIndex index = new Variable(name); + theSymbolTable.put(index, item); + return index; + } + + public Type get(SymbolTableIndex index) { + return theSymbolTable.get(index); + } +} -- cgit v1.2.3 From 3b85d64206d232d12864ec46a8b8d42fe6b464bb Mon Sep 17 00:00:00 2001 From: jwansek Date: Sun, 24 Oct 2021 16:08:45 +0100 Subject: updated readme and makefile --- code/simpleSableCCCalulator/Makefile | 5 +++++ code/simpleSableCCCalulator/README.md | 2 ++ 2 files changed, 7 insertions(+) diff --git a/code/simpleSableCCCalulator/Makefile b/code/simpleSableCCCalulator/Makefile index 7c6962b..477422b 100644 --- a/code/simpleSableCCCalulator/Makefile +++ b/code/simpleSableCCCalulator/Makefile @@ -1,4 +1,5 @@ all: + java -jar ../../../sablecc-3.7/lib/sablecc.jar sableCCCalculator.grammar javac sableCCCalculator/*.java javac sableCCCalculator/types/*.java @@ -6,3 +7,7 @@ all: clean: rm -vf sableCCCalculator/*.class rm -vf sableCCCalculator/types/*class + rm -rfv sableCCCalculator/analysis/ + rm -rfv sableCCCalculator/lexer/ + rm -rfv sableCCCalculator/node/ + rm -rvf sableCCCalculator/parser/ diff --git a/code/simpleSableCCCalulator/README.md b/code/simpleSableCCCalulator/README.md index 4c75421..4878685 100644 --- a/code/simpleSableCCCalulator/README.md +++ b/code/simpleSableCCCalulator/README.md @@ -12,6 +12,8 @@ You produce a lexer and parser by running the sablecc .jar file you can download `javac sableCCCalculator/*.java` +I setup a makefil that can be used. First make sure that sablecc is extracted in the directory below `EsotericProject` and just run `make`. + Then we can run the program. For now it only works by reading files. There are some example maths questions in the examples folder: `java sableCCCalculator.Compiler examples/maths.txt` -- cgit v1.2.3 From aa3a6929584eaa63cafb73353a62effd75d4dd8c Mon Sep 17 00:00:00 2001 From: jwansek Date: Mon, 25 Oct 2021 15:20:30 +0100 Subject: added using symbol table in stack --- code/simpleSableCCCalulator/examples/maths2.txt | 2 +- code/simpleSableCCCalulator/examples/maths4.txt | 2 +- .../sableCCCalculator/ProgramStack.java | 26 +++++----- .../sableCCCalculator/SymbolTable.java | 17 ++++++- .../sableCCCalculator/Translation.java | 58 +++++++++++----------- 5 files changed, 62 insertions(+), 43 deletions(-) diff --git a/code/simpleSableCCCalulator/examples/maths2.txt b/code/simpleSableCCCalulator/examples/maths2.txt index 1f1d63e..313296b 100644 --- a/code/simpleSableCCCalulator/examples/maths2.txt +++ b/code/simpleSableCCCalulator/examples/maths2.txt @@ -1 +1 @@ -sin(45 * 3) / 3 \ No newline at end of file +sin(45 * 2) / 3 diff --git a/code/simpleSableCCCalulator/examples/maths4.txt b/code/simpleSableCCCalulator/examples/maths4.txt index 5b3e67d..a922b77 100644 --- a/code/simpleSableCCCalulator/examples/maths4.txt +++ b/code/simpleSableCCCalulator/examples/maths4.txt @@ -1 +1 @@ -2 + 3.1 +2 + 2 diff --git a/code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java b/code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java index c1046ee..b49c0d1 100644 --- a/code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java +++ b/code/simpleSableCCCalulator/sableCCCalculator/ProgramStack.java @@ -1,29 +1,31 @@ package sableCCCalculator; +import sableCCCalculator.SymbolTable.SymbolTableIndex; import sableCCCalculator.types.*; import java.util.Stack; -public class ProgramStack extends Stack { +public class ProgramStack extends Stack { - public String toString() { + public String toString(SymbolTable table) { String out = "Stack is now: ["; for (int i = 0; i < this.size(); i++) { // String theStr = this.elementAt(i).toString(); // out += String.format("%s, ", theStr.substring(0, theStr.length() - 1)); - out += String.format("%s, ", this.elementAt(i).toString()); + out += String.format("%s, ", table.get(this.elementAt(i))); } return out.substring(0, out.length() - 2) + "]"; } public static void main(String[] args) { - ProgramStack myStack = new ProgramStack<>(); - myStack.add(new Int(2)); - myStack.add(new Int(4)); - myStack.add(new Int(6)); - myStack.add(new Int(0)); - myStack.add(new Int(1)); - myStack.add(new Decimal(24601.10642)); + ProgramStack myStack = new ProgramStack(); + SymbolTable table = new SymbolTable(); + myStack.add(table.addConstant(new Int(2))); + myStack.add(table.addConstant(new Int(4))); + myStack.add(table.addConstant(new Int(6))); + myStack.add(table.addConstant(new Int(0))); + myStack.add(table.addConstant(new Int(1))); + myStack.add(table.addConstant(new Decimal(24601.10642))); - System.out.println(myStack.pop().getText()); - System.out.println(myStack); + System.out.println(table.get(myStack.pop())); + System.out.println(myStack.toString(table)); } } diff --git a/code/simpleSableCCCalulator/sableCCCalculator/SymbolTable.java b/code/simpleSableCCCalulator/sableCCCalculator/SymbolTable.java index 435e48d..992e873 100644 --- a/code/simpleSableCCCalulator/sableCCCalculator/SymbolTable.java +++ b/code/simpleSableCCCalulator/sableCCCalculator/SymbolTable.java @@ -6,7 +6,8 @@ public class SymbolTable { public interface SymbolTableIndex {} - public abstract class Name implements SymbolTableIndex { + public abstract class Name implements SymbolTableIndex { + // can be used for functions too hopefully one day... protected String name; String getName() { @@ -42,7 +43,21 @@ public class SymbolTable { return index; } + public void updateVariable(Type newItem, SymbolTableIndex index) { + theSymbolTable.replace(index, newItem); + } + public Type get(SymbolTableIndex index) { return theSymbolTable.get(index); } + + public static void main(String[] args) { + SymbolTable symbolTable = new SymbolTable(); + symbolTable.addConstant(new Int(3)); + SymbolTableIndex i_var = symbolTable.addVariable(new Int(0), "i"); + System.out.println(symbolTable.get(i_var)); + symbolTable.updateVariable(symbolTable.get(i_var).add(new Int(1)), i_var); + System.out.println(symbolTable.get(i_var)); + } } + \ No newline at end of file diff --git a/code/simpleSableCCCalulator/sableCCCalculator/Translation.java b/code/simpleSableCCCalulator/sableCCCalculator/Translation.java index a673edb..737ecbd 100644 --- a/code/simpleSableCCCalulator/sableCCCalculator/Translation.java +++ b/code/simpleSableCCCalulator/sableCCCalculator/Translation.java @@ -1,88 +1,90 @@ package sableCCCalculator; +import sableCCCalculator.SymbolTable.SymbolTableIndex; import sableCCCalculator.analysis.*; import sableCCCalculator.types.*; import sableCCCalculator.node.*; class Translation extends DepthFirstAdapter { - private ProgramStack programStack = new ProgramStack<>(); + private ProgramStack programStack = new ProgramStack(); + private SymbolTable symbolTable = new SymbolTable(); public void caseTNumber(TNumber node) { System.out.println("Pushing " + Integer.parseInt(node.getText()) + " to stack"); - programStack.push(new Int(node.getText())); - System.out.println(programStack); + programStack.push(symbolTable.addConstant(new Int(node.getText()))); + System.out.println(programStack.toString(symbolTable)); } public void caseTDouble(TDouble node) { System.out.println("Pushing a double: " + Double.parseDouble(node.getText())); - programStack.push(new Decimal(node.getText())); - System.out.println(programStack); + programStack.push(symbolTable.addConstant(new Decimal(node.getText()))); + System.out.println(programStack.toString(symbolTable)); } public void outASineTerm(ASineTerm node) { - Double num = Double.parseDouble(programStack.pop().getText()); + Double num = Double.parseDouble(symbolTable.get(programStack.pop()).toString()); System.out.println("Popped " + num); Double out = Math.sin(Math.toRadians(num)); - programStack.push(new Decimal(out)); + programStack.push(symbolTable.addConstant(new Decimal(out))); System.out.println("Pushed sin(" + num + ") = " + out + " to stack"); - System.out.println(programStack); + System.out.println(programStack.toString(symbolTable)); } public void outAPlusExpr(APlusExpr node) { - Type op2 = programStack.pop(); - Type op1 = programStack.pop(); + Type op2 = symbolTable.get(programStack.pop()); + Type op1 = symbolTable.get(programStack.pop()); System.out.println("Popped " + op1 + " and " + op2 + " from stack"); Type out = op1.add(op2); - programStack.push(out); + programStack.push(symbolTable.addConstant(out)); System.out.println("Pushed " + op1 + "+" + op2 + "=" + out + " to stack"); - System.out.println(programStack); + System.out.println(programStack.toString(symbolTable)); } public void outAMinusExpr(AMinusExpr node) { - Type op2 = programStack.pop(); - Type op1 = programStack.pop(); + Type op2 = symbolTable.get(programStack.pop()); + Type op1 = symbolTable.get(programStack.pop()); System.out.println("Popped " + op1 + " and " + op2 + " from stack"); Type out = op1.sub(op2); - programStack.push(out); + programStack.push(symbolTable.addConstant(out)); System.out.println("Pushed " + op1 + "-" + op2 + "=" + out + " to stack"); - System.out.println(programStack); + System.out.println(programStack.toString(symbolTable)); } public void outAMultFactor(AMultFactor node) { - Type op2 = programStack.pop(); - Type op1 = programStack.pop(); + Type op2 = symbolTable.get(programStack.pop()); + Type op1 = symbolTable.get(programStack.pop()); System.out.println("Popped " + op1 + " and " + op2 + " from stack"); Type out = op1.mult(op2); - programStack.push(out); + programStack.push(symbolTable.addConstant(out)); System.out.println("Pushed " + op1 + "*" + op2 + "=" + out + " to stack"); - System.out.println(programStack); + System.out.println(programStack.toString(symbolTable)); } public void outADivFactor(ADivFactor node) { - Type op2 = programStack.pop(); - Type op1 = programStack.pop(); + Type op2 = symbolTable.get(programStack.pop()); + Type op1 = symbolTable.get(programStack.pop()); System.out.println("Popped " + op1 + " and " + op2 + " from stack"); Type out = op1.div(op2); - programStack.push(out); + programStack.push(symbolTable.addConstant(out)); System.out.println("Pushed " + op1 + "/" + op2 + "=" + out + " to stack"); - System.out.println(programStack); + System.out.println(programStack.toString(symbolTable)); } public void outAModFactor(AModFactor node) { - Type op2 = programStack.pop(); - Type op1 = programStack.pop(); + Type op2 = symbolTable.get(programStack.pop()); + Type op1 = symbolTable.get(programStack.pop()); System.out.println("Popped " + op1 + " and " + op2 + " from stack"); Type out = op1.mod(op2); - programStack.push(out); + programStack.push(symbolTable.addConstant(out)); System.out.println("Pushed " + op1 + "%" + op2 + "=" + out + " to stack"); - System.out.println(programStack); + System.out.println(programStack.toString(symbolTable)); } } -- cgit v1.2.3