From af63e4e526882e10a506c6aaa818844e2c21adad Mon Sep 17 00:00:00 2001 From: Luiz Janeiro Date: Wed, 15 Mar 2017 14:35:55 -0300 Subject: [PATCH] Adicionando operacao de atribuicao --- .gitignore | 54 +- .ide/README.md | 12 +- LICENSE | 42 +- README.md | 422 +-- doc/eplan-compiler.tex | 3126 ++++++++++---------- doc/images/tree.dot | 44 +- driver | 24 +- pom.xml | 290 +- run | 42 +- src/main/cup/parser.cup | 244 +- src/main/java/absyn/AST.java | 44 +- src/main/java/absyn/Dec.java | 32 +- src/main/java/absyn/DecVar.java | 92 +- src/main/java/absyn/Exp.java | 60 +- src/main/java/absyn/ExpAssign.java | 42 + src/main/java/absyn/ExpBinOp.java | 148 +- src/main/java/absyn/ExpBool.java | 54 +- src/main/java/absyn/ExpCall.java | 146 +- src/main/java/absyn/ExpInt.java | 54 +- src/main/java/absyn/ExpLet.java | 76 +- src/main/java/absyn/ExpNegate.java | 74 +- src/main/java/absyn/ExpReal.java | 54 +- src/main/java/absyn/ExpSeq.java | 66 +- src/main/java/absyn/ExpVar.java | 56 +- src/main/java/absyn/Var.java | 60 +- src/main/java/absyn/VarSimple.java | 64 +- src/main/java/env/Env.java | 82 +- src/main/java/env/Table.java | 166 +- src/main/java/error/CompilerError.java | 36 +- src/main/java/error/ErrorHelper.java | 46 +- src/main/java/error/FatalError.java | 26 +- src/main/java/main/Driver.java | 378 +-- src/main/java/main/SemantGui.java | 556 ++-- src/main/java/parse/Loc.java | 128 +- src/main/java/semantic/SemanticHelper.java | 80 +- src/main/java/types/BOOL.java | 28 +- src/main/java/types/FUNCTION.java | 58 +- src/main/java/types/INT.java | 28 +- src/main/java/types/REAL.java | 28 +- src/main/java/types/Type.java | 66 +- src/main/java/types/UNIT.java | 30 +- src/main/jflex/lexer.jflex | 199 +- src/test/java/Test/SemantTest.java | 184 +- tests/test-lexer-01.eplan | 6 +- 44 files changed, 3796 insertions(+), 3751 deletions(-) create mode 100644 src/main/java/absyn/ExpAssign.java diff --git a/.gitignore b/.gitignore index d2f30a1..b888836 100644 --- a/.gitignore +++ b/.gitignore @@ -1,27 +1,27 @@ -# -- Java -# -- virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -# -- Maven -target/* - -# -- IntelliJ IDEA -.idea -*.iml - -# Latex build -doc/_build - -# -- Emacs -*~ - -# output of running the eplan compiler -tests/*.dot* -tests/*.exe -tests/*.ll -tests/*.s - -unknown.dot* -unknown.exe -unknown.ll -unknown.s +# -- Java +# -- virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +# -- Maven +target/* + +# -- IntelliJ IDEA +.idea +*.iml + +# Latex build +doc/_build + +# -- Emacs +*~ + +# output of running the eplan compiler +tests/*.dot* +tests/*.exe +tests/*.ll +tests/*.s + +unknown.dot* +unknown.exe +unknown.ll +unknown.s diff --git a/.ide/README.md b/.ide/README.md index 9fd808b..4ebe30c 100644 --- a/.ide/README.md +++ b/.ide/README.md @@ -1,6 +1,6 @@ -IntelliJ IDEA -------------- - -The following IntelliJ IDEA settings are exported (File/Export Setting): - -* Code Style +IntelliJ IDEA +------------- + +The following IntelliJ IDEA settings are exported (File/Export Setting): + +* Code Style diff --git a/LICENSE b/LICENSE index f08d0d8..e91e333 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2016 José Romildo Malaquias - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2016 José Romildo Malaquias + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index cc05cca..badf7f6 100644 --- a/README.md +++ b/README.md @@ -1,211 +1,211 @@ -# EPLan - -EPLan is an educational programming language for compiler construction -teaching. - -EPlan is used to teach compilation techniques to undergraduate students -at Universidade Federal de Ouro. The language specification starts with -a very minimal kernel and grows with new features as new techniques are -learnt. - -Tags will be used to give access to each important stage of the -compiler implementation. - -## Development tools needed - -- [GIT](https://git-scm.com/) -- [Java development kit](http://www.oracle.com/technetwork/java/javase/downloads/) (version 1.8 or greater) -- C compiler -- [Maven](https://maven.apache.org/) -- Text editor for software development (Suggested: [Atom](https://atom.io/), [Notepad++](https://notepad-plus-plus.org/), gedit, [Emacs](https://www.gnu.org/software/emacs/)) -- IDE for Java development (optional) (suggested: [IntelliJ IDEA](https://www.jetbrains.com/idea/)) - -## Notice about using Windows - -One of the library dependencies of the project (`javacpp-presets-llvm`) -currently is not available for Windows, and because of that the Windows -platform is not supported at the moment. - -## Initial setup to work with EPlan in BCC328 - -In order to develop the activities of the BCC328 (Compiler Construction) course you should: - -- Have a [github](https://github.com/) account. If you do not have one, visit the github site and [sign up](https://github.com/join). -- [Log in](https://github.com/login) the github. -- Visit the [EPLan](https://github.com/romildo/eplan) project page. -- Fork the EPlan project. -![forking](images/fork.png) -- In your computer clone your fork of the eplan project. Notice that in the commands that follow any text written between angular braces `<>` shold be replaced by an appropriate text. For instance ` -$ git clone https://github.com/romildo/eplan.git -$ cd eplan -``` -- Set the remote repository for your clone -``` -$ git remote add upstream https://github.com/romildo/eplan.git -$ git remote -v -``` - -## When testing a version of the eplan compiler - -- Change your working directory to the folder containing your clone. -``` -$ cd -``` -- Select the master branch of the clone of your forked project. -``` -$ git branch -$ git checkout master -``` -- Pull the latest changes from the remote repository. -``` -$ git pull upstream master -``` -- Select the appropriate branch for the activity. -``` -$ git checkout -b -``` -- Develop the activity. - -## To submit an activity - -- Select the master branch of the clone of your forked project. -``` -$ cd -$ git checkout master -``` -- Pull the latest changes from the remote repository. -``` -$ git pull upstream master -``` -- Create a new branch where you will develop the activity. -``` -$ git checkout -b -``` -- Develop the activity. -- See the status of your cloned repository: -``` -git status -``` -- Add any new or modified file to the revision history: -``` -git add -``` -- Commit the changes: -``` -git commit -m -``` -- Push your changes to your forked project. -``` -git push origin -``` -- Make a pull request (PR) from your forked project at github. - -## Some useful commands - -### To remove the generated files - -``` -$ mvn clean -``` - -### To compile the project - -``` -$ mvn compile - -``` - -### To make `jar` files of the project - -``` -$ mvn package -``` - -### To run the eplan compiler - -The EPlan compiler accepts some command line options. A summary of its -usage can be obtained with the `--help` option: - -``` -$ java -jar target/uber-eplan-0.1-SNAPSHOT.jar --help -``` - -Run the EPLan compiler with the command line: - -``` -$ java -jar target/uber-eplan-0.1-SNAPSHOT.jar [options] [file] -``` - -Or you may use the provided shell script `driver`: - -``` -$ ./driver -``` - -There is also the `run` script, which runs the compiler on the standard -input, and generates and runs the executable. It also shows the image of -the abstract syntax tree. For that the -[Graphviz](http://www.graphviz.org/) package is needed. - -``` -$ ./run -``` - -The current version of the library `javacpp-presets-llvm` is based on a -LLVM release that has an issue regarding floating point constants in the -LLVM IR language. It follows the locale setting for numeric formatting -and at the same time it does not accept a comma instead of a dot in the -literal. You may have to set you locale numeric setting to `en_US-UTF-8` -for it to work. - -``` -$ LC_NUMERIC=en_US-UTF-8 java -jar target/uber-eplan-0.1-SNAPSHOT.jar [options] [file] -``` - -or with the provided shell script `driver`: - -``` -$ LC_NUMERIC=en_US-UTF-8 ./driver -``` - -A better alternative may be setting your language to `en_US-UTF-8` in -the system configuration. - -The generated LLVM intermediate representation code should be compiled -with the `llc`: - -``` -$ llc .ll -``` - -The generated assembly code and the runtime library should be compiled and linked with a C compiler. If using CLang: - -``` -$ clang -o .exe src/main/c/bindings.c .s -``` - -Or if using GCC: - -``` -$ gcc -o .exe .s src/main/c/bindings.c -``` - -To get an image of the syntact tree of your program: - -``` -$ dot -O -Tpng .dot .dot -$ eog .dot.png -``` - -Finally run the binary obtained for the eplan source code: - -``` -$ ./.exe -``` - -These steps can be combined in a single command line: -``` -$ F= && ./driver $F && llc $F.ll && clang -o $F.exe $F.s src/main/c/bindings.c && dot -O -Tpng $F.dot && eog $F*png && ./$F.exe -``` +# EPLan + +EPLan is an educational programming language for compiler construction +teaching. + +EPlan is used to teach compilation techniques to undergraduate students +at Universidade Federal de Ouro. The language specification starts with +a very minimal kernel and grows with new features as new techniques are +learnt. + +Tags will be used to give access to each important stage of the +compiler implementation. + +## Development tools needed + +- [GIT](https://git-scm.com/) +- [Java development kit](http://www.oracle.com/technetwork/java/javase/downloads/) (version 1.8 or greater) +- C compiler +- [Maven](https://maven.apache.org/) +- Text editor for software development (Suggested: [Atom](https://atom.io/), [Notepad++](https://notepad-plus-plus.org/), gedit, [Emacs](https://www.gnu.org/software/emacs/)) +- IDE for Java development (optional) (suggested: [IntelliJ IDEA](https://www.jetbrains.com/idea/)) + +## Notice about using Windows + +One of the library dependencies of the project (`javacpp-presets-llvm`) +currently is not available for Windows, and because of that the Windows +platform is not supported at the moment. + +## Initial setup to work with EPlan in BCC328 + +In order to develop the activities of the BCC328 (Compiler Construction) course you should: + +- Have a [github](https://github.com/) account. If you do not have one, visit the github site and [sign up](https://github.com/join). +- [Log in](https://github.com/login) the github. +- Visit the [EPLan](https://github.com/romildo/eplan) project page. +- Fork the EPlan project. +![forking](images/fork.png) +- In your computer clone your fork of the eplan project. Notice that in the commands that follow any text written between angular braces `<>` shold be replaced by an appropriate text. For instance ` +$ git clone https://github.com/romildo/eplan.git +$ cd eplan +``` +- Set the remote repository for your clone +``` +$ git remote add upstream https://github.com/romildo/eplan.git +$ git remote -v +``` + +## When testing a version of the eplan compiler + +- Change your working directory to the folder containing your clone. +``` +$ cd +``` +- Select the master branch of the clone of your forked project. +``` +$ git branch +$ git checkout master +``` +- Pull the latest changes from the remote repository. +``` +$ git pull upstream master +``` +- Select the appropriate branch for the activity. +``` +$ git checkout -b +``` +- Develop the activity. + +## To submit an activity + +- Select the master branch of the clone of your forked project. +``` +$ cd +$ git checkout master +``` +- Pull the latest changes from the remote repository. +``` +$ git pull upstream master +``` +- Create a new branch where you will develop the activity. +``` +$ git checkout -b +``` +- Develop the activity. +- See the status of your cloned repository: +``` +git status +``` +- Add any new or modified file to the revision history: +``` +git add +``` +- Commit the changes: +``` +git commit -m +``` +- Push your changes to your forked project. +``` +git push origin +``` +- Make a pull request (PR) from your forked project at github. + +## Some useful commands + +### To remove the generated files + +``` +$ mvn clean +``` + +### To compile the project + +``` +$ mvn compile + +``` + +### To make `jar` files of the project + +``` +$ mvn package +``` + +### To run the eplan compiler + +The EPlan compiler accepts some command line options. A summary of its +usage can be obtained with the `--help` option: + +``` +$ java -jar target/uber-eplan-0.1-SNAPSHOT.jar --help +``` + +Run the EPLan compiler with the command line: + +``` +$ java -jar target/uber-eplan-0.1-SNAPSHOT.jar [options] [file] +``` + +Or you may use the provided shell script `driver`: + +``` +$ ./driver +``` + +There is also the `run` script, which runs the compiler on the standard +input, and generates and runs the executable. It also shows the image of +the abstract syntax tree. For that the +[Graphviz](http://www.graphviz.org/) package is needed. + +``` +$ ./run +``` + +The current version of the library `javacpp-presets-llvm` is based on a +LLVM release that has an issue regarding floating point constants in the +LLVM IR language. It follows the locale setting for numeric formatting +and at the same time it does not accept a comma instead of a dot in the +literal. You may have to set you locale numeric setting to `en_US-UTF-8` +for it to work. + +``` +$ LC_NUMERIC=en_US-UTF-8 java -jar target/uber-eplan-0.1-SNAPSHOT.jar [options] [file] +``` + +or with the provided shell script `driver`: + +``` +$ LC_NUMERIC=en_US-UTF-8 ./driver +``` + +A better alternative may be setting your language to `en_US-UTF-8` in +the system configuration. + +The generated LLVM intermediate representation code should be compiled +with the `llc`: + +``` +$ llc .ll +``` + +The generated assembly code and the runtime library should be compiled and linked with a C compiler. If using CLang: + +``` +$ clang -o .exe src/main/c/bindings.c .s +``` + +Or if using GCC: + +``` +$ gcc -o .exe .s src/main/c/bindings.c +``` + +To get an image of the syntact tree of your program: + +``` +$ dot -O -Tpng .dot .dot +$ eog .dot.png +``` + +Finally run the binary obtained for the eplan source code: + +``` +$ ./.exe +``` + +These steps can be combined in a single command line: +``` +$ F= && ./driver $F && llc $F.ll && clang -o $F.exe $F.s src/main/c/bindings.c && dot -O -Tpng $F.dot && eog $F*png && ./$F.exe +``` diff --git a/doc/eplan-compiler.tex b/doc/eplan-compiler.tex index 33119f5..e3adc6b 100644 --- a/doc/eplan-compiler.tex +++ b/doc/eplan-compiler.tex @@ -1,1563 +1,1563 @@ -\documentclass[smaller]{beamer} - -\usepackage{iftex} - -\RequireLuaTeX - -\usepackage[]{fontspec} -\usepackage[brazilian]{babel} - -\usepackage{dirtree} -\usepackage{tikz-qtree} -\usepackage{syntax} -\usepackage{pygmentex} -% \usepackage{jrmmisc} -\usepackage{tcolorbox} -\usepackage{relsize} -\usepackage{indentfirst} - -% \setmainfont{Times New Roman} -% \setsansfont[Scale=MatchLowercase]{Helvetica} -% \setmonofont[Scale=MatchLowercase]{Courier} - -% \setmainfont{Times New Roman} -% \setsansfont[Scale=MatchLowercase]{Helvetica LT Std} -% \setmonofont[Scale=MatchLowercase]{Courier Std} - -% \setmainfont{DejaVu Serif} -% \setsansfont[Scale=MatchLowercase]{DejaVu Sans} -% \setmonofont[Scale=MatchLowercase]{DejaVu Sans Mono} - -\setmainfont{Liberation Serif} -\setsansfont[Scale=MatchLowercase]{Liberation Sans} -\setmonofont[Scale=MatchLowercase]{Liberation Mono} - -% \setmainfont{Lucida Std} -% \setsansfont[Scale=MatchLowercase]{Lucida Sans Std} -% \setmonofont[Scale=MatchLowercase]{Lucida Sans Typewriter Std} -% % \setmonofont[Scale=MatchLowercase]{Lucida Typewriter Std} - -% \setmainfont{Luxi Serif} -% \setsansfont[Scale=MatchLowercase]{Luxi Sans} -% \setmonofont[Scale=MatchLowercase]{Luxi Mono} - -% \setmainfont{Nimbus Roman No9 L} -% \setsansfont[Scale=MatchLowercase]{Nimbus Sans L} -% \setmonofont[Scale=MatchLowercase]{Nimbus Mono L} - -% \setmainfont{Droid Serif} -% \setsansfont[Scale=MatchLowercase]{Droid Sans} -% \setmonofont[Scale=MatchLowercase]{Droid Sans Mono} % no bold - -% \setmonofont[Scale=MatchLowercase]{Anonymous Pro} -% \setmonofont[Scale=MatchLowercase]{Consolas} -% \setmonofont[Scale=MatchLowercase]{Courier New} -% \setmonofont[Scale=MatchLowercase]{Cousine} -% \setmonofont[Scale=MatchLowercase]{DejaVu Sans Mono} -% \setmonofont[Scale=MatchLowercase]{Fantasque Sans Mono} -% \setmonofont[Scale=MatchLowercase]{Fira Code} -% \setmonofont[Scale=MatchLowercase]{Fira Mono} -% \setmonofont[Scale=MatchLowercase]{FreeMono} -% \setmonofont[Scale=MatchLowercase]{Hack} -% \setmonofont[Scale=MatchLowercase]{Input Mono Condensed} -% \setmonofont[Scale=MatchLowercase]{Iosevka Slab} -% \setmonofont[Scale=MatchLowercase]{Iosevka} -% \setmonofont[Scale=MatchLowercase]{Liberation Mono} -% \setmonofont[Scale=MatchLowercase]{Noto Mono} -% \setmonofont[Scale=MatchLowercase]{Source Code Pro} -% \setmonofont[Scale=MatchLowercase]{SF Mono} -% \setmonofont[Scale=MatchLowercase]{Ubuntu Mono} -\setmonofont[Scale=MatchLowercase]{M+ 1m} -% % -% \setmonofont[Scale=MatchLowercase]{Letter Gothic Std} -% \setmonofont[Scale=MatchLowercase]{Lucida Sans Typewriter Std} -% \setmonofont[Scale=MatchLowercase]{Luxi Mono} - - -\setbeamercovered{transparent} -\hypersetup{colorlinks} -\usetheme{OuroPreto} - -\newenvironment{tips}{% - \textbf{Dicas:}\newline - \begin{list}{*}{% - \setlength{\topsep}{0pt}% - \setlength{\itemsep}{0pt}% - \setlength{\parsep}{0pt}% - }% - }{% - \end{list}% -} - -\usetikzlibrary{ - calc, - shapes.multipart, - chains, - arrows, - graphs, - graphdrawing, -} - -\usegdlibrary{ - layered -} - -\tikzset{ - joined/.style = { - join=by ->, - }, - cons/.style = { - draw, - rounded corners, - rectangle split, - rectangle split parts=2, - rectangle split horizontal, - joined, - }, - var/.style = { - blue, - joined, - }, - null/.style = { - fill, - circle, - inner sep=0mm, - minimum size=2mm, - joined, - }, -} - -\renewcommand{\DTcomment}[1]{\textcolor{yellow}{\hrulefill}\sffamily\textcolor{blue}{#1}} -% \renewcommand\DTstylecomment{\sffamily\color{green}\textsc} -\renewcommand\DTstyle{\ttfamily\textcolor{red}} -\setlength{\DTbaselineskip}{12pt} - -\newcommand{\semester}{2016.2} - -\newcommand{\lang}{\textsl{EPLan}} - - -\setpygmented{lang=java,tabsize=3,sty=default} -\efboxsetup{hidealllines,backgroundcolor=yellow!28} - -\mdfsetup{ - % backgroundcolor=green!10, - roundcorner=2pt, - skipabove=2pt, - skipbelow=2pt, - innerleftmargin=2pt, - innerrightmargin=2pt, - innertopmargin=.25\baselineskip, - innerbottommargin=.25\baselineskip, -} - - -% syntax configuration -\renewcommand{\syntleft}{\normalfont\slshape\hspace{0.25em}} -\renewcommand{\syntright}{\hspace{0.25em}} -\renewcommand{\ulitleft}{\normalfont\ttfamily\bfseries\frenchspacing\color{red}\hspace{0.25em}} -\renewcommand{\ulitright}{\hspace{0.25em}} - - - - -\begin{document} - -\title[compiler]{ - Compilador de \lang{} -} -\subject{Linguagens de Programação} -\author{José Romildo Malaquias} -\institute[UFOP]{ - Departamento de Computação\\ - Universidade Federal de Ouro Preto -} -\date{\semester} - -\frame{\titlepage} - -\frame{\tableofcontents} - - -\section{A estrutura do compilador} - - -\begin{frame}{Organização do compilador} - \begin{itemize} - \item Implementado na linguagem \textbf{Java}. - \item Ferramentas auxiliares: - \begin{itemize} - \item \textbf{JFlex}: gerador de analisador léxico - \item \textbf{CUP}: gerador de analisador sintático - \item \textbf{LLVM}: gerador de código - \item \textbf{Maven}: ferramenta de automação de compilação de - projetos Java - \end{itemize} - \item Usa bibliotecas externas: - \begin{itemize} - \item \textbf{commons-lang3}: complementa as classes que estão - em \pyginline|java.lang|. - - \item \textbf{jcommander}: framework Java muito pequeno que - torna trivial a análise de parâmetros de linha de comando - - \item \textbf{javacpp-presets-llvm}: interface para a biblioteca - LLVMC do projeto LLVM (infraestrutura de construçào de - compilador escrita em C++) - - \item \textbf{javaslang}: uma biblioteca funcional para Java 8+ que - fornece tipos de dados persistentes e estruturas de controle - funcionais - - \item \textbf{javaslang-render}: biblioteca de renderização para - algumas estruturas de dados fornecidas por javaslang - - \item \textbf{junit}: \emph{framework} com suporte à criação de testes - automatizados em Java - - \item \textbf{assertj}: fornece um rico conjunto de afirmações, com - mensagens de erro úteis, melhorando a legibilidade dos testes - automatizados em Java - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile]{Maven} - \begin{itemize} - \item Usado para automatizar a compilação de projetos. - \item O projeto é configurado usando um \textbf{POM} (\emph{Project - Object Model)}, que é armazenado em um arquivo \texttt{pom.xml}. - \item O desenvolvimento pode ser feito em várias \textbf{fases}, - indicadas por \textbf{objetivos}, como: - \begin{center} - \begin{tabular}{ll} - \textit{clean} & remover arquivos gerados \\ - \textit{generate-sources} & gerar código automático \\ - \textit{process-resources} & processar recursos \\ - \textit{compile} & compilar \\ - \textit{process-test-resources} & processar recursos de teste \\ - \textit{test-compile} & testar compilação \\ - \textit{test} & testar \\ - \textit{package} & empacotar \\ - \textit{install} & instalar \\ - \textit{deploy} & implantar - \end{tabular} - \end{center} - \item Exemplo: compilar o projeto na linha de comando: -\begin{Verbatim}[frame=single] -$ mvn compile -\end{Verbatim} - \end{itemize} -\end{frame} - -\begin{frame}{Estrutura de diretórios do projeto} - \small - \noindent - \dirtree{% - .1 \lang{}-compiler. - .2 src\DTcomment{código fonte do projeto}. - .3 main\DTcomment{código fonte principal}. - .4 c\DTcomment{código fonte em C}. - .4 cup\DTcomment{código fonte para o CUP}. - .4 java\DTcomment{código fonte em Java}. - .4 jflex\DTcomment{código fonte para o JFlex}. - .3 test\DTcomment{código fonte dos testes}. - .4 java\DTcomment{código fonte dos testes em Java}. - .2 target\DTcomment{arquivos gerados automaticamente}. - .3 classes\DTcomment{classes geradas pelo compilador de Java}. - .3 generated-sources\DTcomment{código fonte gerado por ferramentas}. - .4 cup\DTcomment{código fonte gerado pelo CUP}. - .4 jflex\DTcomment{código fonte gerado pelo JFlex}. - .3 generated-test-sources\DTcomment{cód. fonte de testes gerado por ferramentas}. - .3 test-classes\DTcomment{classes dos testes geradas pelo compilador de Java}. - .2 pom.xml\DTcomment{arquivo de especificação do projeto}. - } -\end{frame} - -\section{Javaslang} - -\begin{frame}[fragile,allowframebreaks]{Javaslang} - \begin{itemize} - \item Javaslang fornece várias estruturas de dados funcionais, como: - \begin{itemize} - \item tuplas - \item listas - \item árvores - \begin{itemize} - \item Árvores serão amplamente utilizadas para exibir as - estruturas internas do compilador, incluindo as árvores - sintáticas. - \end{itemize} - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.Tuple2}} - \footnotesize -\begin{pygmented}[] -import javaslang.Tuple; -import javaslang.Tuple2; - -public class TestJavaslang { - public static void main(String[] args) { - Tuple2 person = Tuple.of("paul", 17); - - String name = person._1; - Integer age = person._2; - - Tuple2 p = - person.map(n -> n + " jones", - a -> a + 1); - - Tuple2 q = - person.map((n, a) -> Tuple.of(n + " jones", a + 1)); - - String s = person.transform((n, a) -> n + ": " + a); - - System.out.println(s); - } -} -\end{pygmented} -\end{frame} - - - -\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.collection.List}} - \begin{itemize} - \item Exemplos de listas (simplesmente) encadeadas: -\begin{pygmented}[] -List list1 = List.empty(); -List list2 = List.of("nice"); -List list3 = List.of(11, 12, 13); -List list4 = list3.tail(); -List list5 = list4.prepend(10); -\end{pygmented} - \begin{center} - \begin{tikzpicture}[ - cons/.style={draw}, - var/.style={draw=none,blue}, - null/.style={circle,inner sep=0mm,minimum size=1mm}, - ] - - \graph [ - %layered layout, - grow right sep, - nodes={cons}, - ] { - list1[var] -> n1[null,as={}]; - list2[var] -> nice -> n2[null,as={}]; - list3[var] -> 11 -> 12 -> 13 -> n3[null,as={}]; - list4[var] -> 12; - list5[var] -> 10 -> 12; - }; - - \end{tikzpicture} - \end{center} - - \framebreak - - \item Operando com cada elemento de uma lista: -\begin{pygmented}[] -List lst = List.of(10, 20, 30); - -for (Integer x : lst) - System.out.println(x); - -lst.forEach(x -> System.out.println(x)); - -lst.forEach(System.out::println); -\end{pygmented} - - \framebreak - - \item Aplicando uma função a cada elemento da lista e coletando os - resultados em outra lista: -\begin{pygmented}[] -List a = List.of(4.0, 9.0, 25.0); -List c = a.map(Math::sqrt); -List b = a.map(x -> 2*x); -\end{pygmented} - - \framebreak - - \item Reduzindo uma lista: -\begin{pygmented}[] -List a = List.of("1", "2", "3"); -String str = a.fold("", (a1, a2) -> a1 + a2); - -List b = List.of(1, 2, 3, 4); -Integer sum = b.fold(0, (s, x) -> s + x); -\end{pygmented} - - \end{itemize} -\end{frame} - - - - -\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.collection.Tree}} -\begin{pygmented}[] -Tree tree1 = Tree.empty(); -Tree tree2 = Tree.of("nice"); -Tree tree3 = Tree.of(99, 21, 22, 23); -Tree tree4 = Tree.of(10, - Tree.of(5, Tree.of(2)), - Tree.of(7), - Tree.of(0), - Tree.of(19, Tree.of(3), Tree.of(8))); -\end{pygmented} - \begin{center} - \begin{tikzpicture}[ - cons/.style={draw}, - var/.style={draw=none,blue}, - null/.style={circle,inner sep=0mm,minimum size=1mm}, - ] - - \graph [ - layered layout, - %grow right sep, - nodes={cons}, - ] { - tree1[var] -> n1[null,as={}]; - tree2[var] -> nice; - tree3[var] -> 99 -> {21, 22, 23}; - tree4[var] -> 10 -> {5 -> 2, 7, 0, 19 -> {3, 8}}; - }; - - \end{tikzpicture} - \end{center} -\end{frame} - - -\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.render.text.PrettyPrinter}} - \small - \begin{columns}[t] - \begin{column}{.75\textwidth} -\begin{pygmented}[] -import javaslang.collection.Tree; - -import javaslang.render.text.PrettyPrinter; - -final Tree tree = - Tree.of("Ann", - Tree.of("Mary", - Tree.of("John", - Tree.of("Avila")), - Tree.of("Karen", - Tree.of("Frank")), - Tree.of("Steven\nAbbot\nBraddock")), - Tree.of("Peter", - Tree.of("Paul\nPalucci"), - Tree.of("Anthony")), - Tree.of("Christopher", - Tree.of("Samuel"))); - -final String out = PrettyPrinter.pp(tree); -\end{pygmented} - \end{column} - \begin{column}{.25\textwidth} -\begin{Verbatim} -Ann -├──Mary -│ ├──John -│ │ └──Avila -│ ├──Karen -│ │ └──Frank -│ └──Steven -│ Abbot -│ Braddock -├──Peter -│ ├──Paul -│ │ Palucci -│ └──Anthony -└──Christopher - └──Samuel -\end{Verbatim} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.render.text.Boxes}} - \footnotesize -\begin{pygmented}[] -import javaslang.collection.Tree; -import javaslang.render.text.Boxes; - -final Tree tree = /* ... */ - -final String out = Boxes.box(tree).toString(); -\end{pygmented} - -\begin{verbatim} - ┌───┐ - │Ann│ - └─┬─┘ - ┌───────────────┴──────┬────────────────┐ - ┌──┴─┐ ┌──┴──┐ ┌─────┴─────┐ - │Mary│ │Peter│ │Christopher│ - └──┬─┘ └──┬──┘ └─────┬─────┘ - ┌───────┬─┴───────┐ ┌────┴────┐ │ -┌──┴─┐ ┌──┴──┐ ┌────┴───┐ ┌───┴───┐ ┌───┴───┐ ┌───┴──┐ -│John│ │Karen│ │ Steven │ │ Paul │ │Anthony│ │Samuel│ -└──┬─┘ └──┬──┘ │ Abbot │ │Palucci│ └───────┘ └──────┘ - │ │ │Braddock│ └───────┘ -┌──┴──┐ ┌──┴──┐ └────────┘ -│Avila│ │Frank│ -└─────┘ └─────┘ -\end{verbatim} -\end{frame} - - -\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.render.text.DotFile}} - \small - \begin{columns}[t] - \begin{column}{.5\textwidth} -\begin{pygmented}[] -import javaslang.collection.Tree; -import javaslang.render.dot.DotFile; - -final Tree tree = /* ... */; - -DotFile.write(tree, "tree.dot"); -\end{pygmented} - \end{column} - \begin{column}{.5\textwidth} - \begin{itemize} - \item Dot é uma linguagem para descrever grafos. - \item É necessário o pacote \textbf{graphviz}. - \end{itemize} -\begin{Verbatim}[frame=single] -$ dot -Tpng -O tree.dot -\end{Verbatim} - \end{column} - \end{columns} - \begin{center} - \makebox[0pt][r]{\texttt{tree.dot.png}} - \includegraphics[scale=.35]{images/tree.png} - \end{center} -\end{frame} - -\section{Posição no código fonte} - -\begin{frame}[fragile,allowframebreaks]{Localização no código fonte} - \begin{itemize} - \item A localização é usada para reportar erros. - \item Indica onde uma frase do programa começa e termina no código - fonte. - \item Representada pela classe \pyginline|parse.Loc| - \begin{pygmented}[lang=java] -Loc(Location left, Location right) - \end{pygmented} - \item Usa o tipo - \begin{pygmented}[lang=java] -java_cup.runtime.ComplexSymbolFactory.Location - \end{pygmented} - contendo informações como: - \begin{itemize} - \item nome da unidade de compilação (arquivo fonte) - \item número da linha - \item número da coluna - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{Construção da localização} - \begin{itemize} - \item Alguns métodos de fábrica: -\begin{pygmented}[] -import java_cup.runtime.Symbol; -import java_cup.runtime.ComplexSymbolFactory.ComplexSymbol; -import java_cup.runtime.ComplexSymbolFactory.Location; - -/* ... */ - -public static Loc loc() -public static Loc loc(Location left) -public static Loc loc(Location left, Location right) -public static Loc loc(Symbol symbol) -public static Loc loc(Symbol a, Symbol b) -public static Loc loc(ComplexSymbol symbol) -public static Loc loc(ComplexSymbol a, ComplexSymbol b) -\end{pygmented} - - \item \pyginline|Symbol| e \pyginline|ComplexSymbol| representam - símbolos terminais - \end{itemize} -\end{frame} - - -\section{Gerenciamento de erros} - -\begin{frame}[fragile,allowframebreaks]{Reportagem de erro} - \begin{itemize} - \item Os erros são reportados por meio do mecanismo de - \textbf{exceções} de Java. - \item Erros no programa fonte são representados pela classe - \pyginline|error.CompileError|, subclasse de - \pyginline|RuntimeError|. - \item Erros na implementação do compilador são representados pela - classe \pyginline|error.FatalError|, também subclasse de - \pyginline|RuntimeError|. - \item A classe \pyginline|error.ErrorHelper| tem alguns métodos - estáticos que facilitam a criação de objetos de erro: -\begin{pygmented}[] -static CompilerError error(String message) -static CompilerError error(String format, Object... args) -static CompilerError error(Loc loc, String format, Object... args) - -static FatalError fatal(String format, Object... args) -\end{pygmented} - \end{itemize} -\end{frame} - - -\section{Análise léxica} - -\begin{frame}[fragile,allowframebreaks]{Símbolos terminais} - \begin{itemize} - \item Os \textbf{símbolos terminais} são definidos na gramática - livre de contexto do CUP (arquivo - \texttt{src/main/cup/parser.cup}). - \item Exemplos: -\begin{pygmented}[] -terminal String LITREAL; -terminal PLUS, MINUS, TIMES, DIV; -terminal LPAREN, RPAREN; -\end{pygmented} - - \item O CUP gera uma interface \pyginline|parse.SymbolConstants| - contendo a definição de constantes correspondentes aos terminais - que foram declarados. - - \item Quando relevante os terminais podem ter um valor semântico - associado. - - \item A classe \pyginline|ComplexSymbol| é usada para representar - os símbolos terminais, contendo as seguintes informações: - \begin{itemize} - \item classificação (como declarado na gramática) - \item lexema - \item localização (começo e fim) no código fonte - \item valor semântico - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{Regras léxicas} - \begin{itemize} - \item O analisador léxico é gerado pelo \textbf{JFlex}. - \item As regras léxicas são especificadas no arquivo - \alert{\texttt{src/main/jflex/lexer.jflex}}. - \item O JFlex cria a classe \pyginline|parse.Lexer| compatível com - o CUP. - \item Os \textbf{lexemas} (palavras que formam os símbolos - léxicos) são descritos por \textbf{expressões regulares}. - \item A classificação so símbolo terminal é feita na \textbf{ação - semântica} (código em Java que faz parte da regra léxica). - \item Para facilitar a criação dos diversos símbolos léxicos - recomenda-se o uso dos \alert{métodos auxiliares} (definidos no - próprio arquivo de especificação): -\begin{pygmented}[] -private Symbol tok(int type, String lexeme, Object value) -private Symbol tok(int type, Object value) -private Symbol tok(int type) -\end{pygmented} - \end{itemize} -\end{frame} - - -\begin{frame}[fragile,allowframebreaks]{Exemplo de regras léxicas} -\begin{pygmented}[lang=text] -[ \t\f\n\r]+ { /* skip */ } - -[0-9]+ ("." [0-9]+)? { return tok(LITREAL, yytext()); } - -"+" { return tok(PLUS); } -"-" { return tok(MINUS); } -"*" { return tok(TIMES); } -"/" { return tok(DIV); } -"(" { return tok(LPAREN); } -")" { return tok(RPAREN); } - -. { throw error(Loc.loc(locLeft()), - "unexpected char '%s'", - yytext()); } -\end{pygmented} -\end{frame} - - -\section{Análise sintática} - -\begin{frame}[fragile,allowframebreaks]{Análise sintática} - \begin{itemize} - \item A especificação sintática (\textbf{gramática livre de - contexto}) é feita no arquivo - \alert{\texttt{src/main/cup/parser.cup}}. - \item Algumas opções de execução do CUP são indicadas no arquivo - \alert{\texttt{pom.xml}}. - \item O analisador sintático é gerado pelo \textbf{CUP}, que cria - a classe \pyginline|parse.Parser| e a interface - \pyginline|parse.SymbolConstants|. - \item Na gramática livre de contexto são especificados: - \begin{itemize} - \item os símbolos terminais - \item os símbols não terminais - \item o símbolo inicial - \item as regras de produção - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{Ações semânticas} - \begin{itemize} - \item Quando um símbolo (terminal ou não terminal) tem um - \textbf{valor semântico}, o tipo do valor semântico é informado na - declaração do símbolo. - \item O cálculo do valor semântico do símbolo no lado esquerdo de - uma regra de produção é feito usando os valores semênticas dos - símbolos que aparecem no lado direiro da regra através de uma - \textbf{ação semântica} (código em Java). - \item Quando um \alert{nome} é associado a um símbolo no lado - direito de uma regra (por exemplo \pyginline|exp:nome|), o CUP - cria três variáveis (no exemplo \pyginline|nome|, - \pyginline|nomexleft| e \pyginline|nomexright|) no codigo gerado, - contendo o valor semântico, a localização esquerda (onde começa no - código fonte), e a localização direita (onde termina no código - fonte) do símbolo, respectivamente. - \end{itemize} -\end{frame} - - -\begin{frame}[fragile,allowframebreaks]{Exemplo de gramática para o CUP} - \scriptsize -\begin{pygmented}[] -terminal String LITREAL; -terminal PLUS, MINUS, TIMES, DIV; -terminal LPAREN, RPAREN; - -non terminal Exp exp; -non terminal Exp term; -non terminal Exp factor; - -start with exp; - -exp ::= - exp:x PLUS term:y {: RESULT = new ExpBinOp(ExpBinOp.Op.PLUS, x, y); :} -| exp:x MINUS term:y {: RESULT = new ExpBinOp(ExpBinOp.Op.MINUS, x, y); :} -| term:x {: RESULT = x; :} -; - -term ::= -| term:x TIMES factor:y {: RESULT = new ExpBinOp(ExpBinOp.Op.TIMES, x, y); :} -| term:x DIV factor:y {: RESULT = new ExpBinOp(ExpBinOp.Op.DIV, x, y); :} -| factor:x {: RESULT = x; :} -; - -factor ::= - LITREAL:x {: RESULT = new ExpReal(x); :} -| LPAREN exp:x RPAREN {: RESULT = x; :} -; -\end{pygmented} -\end{frame} - - -\section{Árvores sintáticas} - -\begin{frame}[fragile,allowframebreaks]{Árvores sintáticas} - \begin{itemize} - \item \textbf{Árvore sintática} é uma \alert{estrutura de dados - hierárquica} que representa a estrutura sintática do programa - fonte. - \item A \textbf{raiz} da árvore é o \alert{símbolo inicial} da - gramática. - \item As \textbf{folhas} são os \alert{símbolos terminais} que, - lidos da esquerda para a direita, correspondem ao programa fonte. - \item Pode ser: - \begin{itemize} - \item \textbf{concreta}: todos os símbolos na sequência de - derivação são colocados na árvore - \item \textbf{abstrata}: apenas as informações relevantes para o - entendimento da estrutura do programa são mantidos na árvore - \end{itemize} - \item A saída do \textbf{analisador sintático} é uma árvore - sintática abstrata (\alert{AST}). - \end{itemize} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{Representação} - \begin{itemize} - \item A representação das árvores sintáticas é feita através de - classes no pacote \pyginline|absyn|. - \item A classe abstrata \pyginline|absyn.AST| é superclasse de - todas as árvores sintáticas abstratas. - \item Esta classe implementa a interface \pyginline|ToTree|: -\begin{pygmented}[] -package javaslang.render; - -import javaslang.collection.Tree; - -public interface ToTree { - public abstract Tree.Node toTree(); -} -\end{pygmented} - \item O método \pyginline|toTree| converte a árvore abstrata em - uma estrutura de dados geral para árvores cujos nós armazenam - strings, útil na apresentação visual da árvore sintática. - \end{itemize} -\end{frame} - - -\begin{frame}[fragile,allowframebreaks]{Definindo as árvores abstratas} - \begin{itemize} - \item Para cada \alert{categoria sintática} (como expressões, - comandos, ou declarações) reprentada por um \textbf{símbolo não - terminal} definimos uma subclasse abstrata de - \pyginline|absyn.AST|. - \item Para cada \alert{forma} da categoria sintática para um não - terminal (como as formas de expressão: expressão constante, - operação binária, chamada de função, etc.), representada por uma - \textbf{regra de produção}, definamos uma subclasse da classe que - representa aquela forma específica da categoria sintática. - \item - Nesta classe deve-se: - \begin{itemize} - \item definir os \alert{campos} necessários para os componentes - (sub-árvores) da árvore sintática, - \item definir \alert{construtores} que inicializam estes campos - com valores passados como argumentos, - \item definir o método \pyginline|toTree|. - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{A classe AST} -\begin{pygmented}[] -package absyn; - -import javaslang.render.ToTree; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -public abstract class AST implements ToTree { - - @Override - public String toString() { - return ToStringBuilder.reflectionToString( - this, - ToStringStyle.SHORT_PREFIX_STYLE); - } - -} -\end{pygmented} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{A classe Exp} -\begin{pygmented}[] -package absyn; - -public abstract class Exp extends AST { -} -\end{pygmented} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{A classe ExpReal} -\begin{pygmented}[] -package absyn; - -import javaslang.collection.Tree; - -public class ExpReal extends Exp { - - public final String value; - - public ExpReal(String value) { - this.value = value; - } - - @Override - public Tree.Node toTree() { - return Tree.of("ExpReal: " + value); - } -} -\end{pygmented} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{A classe ExpReal} - \relscale{0.78} -\begin{pygmented}[] -package absyn; - -import javaslang.collection.Tree; - -public class ExpBinOp extends Exp { - - public enum Op {PLUS, MINUS, TIMES, DIV} - - public final Op op; - public final Exp left; - public final Exp right; - - public ExpBinOp(Op op, Exp left, Exp right) { - this.op = op; - this.left = left; - this.right = right; - } - - @Override - public Tree.Node toTree() { - return Tree.of("ExpBinOp: " + op, left.toTree(), right.toTree()); - } -} -\end{pygmented} -\end{frame} - - -\section{Geração de código} - -\begin{frame}[fragile,allowframebreaks]{Representação intermediária} - \begin{itemize} - \item A árvore sintática do programa fonte é traduzida para uma - representação intermediária do código fonte. - \item Usaremos a representação intermediária do framework - \textbf{LLVM}. - \item A biblioteca Java \texttt{javacpp-presets-llvm} será usada - para criar a representação intermediária. - \item A classe \pyginline|absyn.Exp| deve ter um método abstrato - para converter uma expressão para a sua representação - intermediária. -\begin{pygmented}[] -import static org.bytedeco.javacpp.LLVM.*; -/* ... */ -public abstract LLVMValueRef translate(LLVMModuleRef module, - LLVMBuilderRef builder); -\end{pygmented} - \item Suas subclasses devem implementar este método. - \end{itemize} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{Representação intermediária de constantes} -\begin{pygmented}[] -package absyn; - -// ... -import static org.bytedeco.javacpp.LLVM.*; - -public class ExpReal extends Exp { - // ... - - @Override - public LLVMValueRef translate(LLVMModuleRef module, - LLVMBuilderRef builder) { - return LLVMConstRealOfString(LLVMDoubleType(), value); - } -} -\end{pygmented} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{Representação intermediária de operação binária} - \relscale{0.76} -\begin{pygmented}[] -package absyn; - -// ... -import static org.bytedeco.javacpp.LLVM.*; -import static error.ErrorHelper.fatal; - -public class ExpBinOp extends Exp { - // ... - - @Override - public LLVMValueRef translate(LLVMModuleRef module, LLVMBuilderRef builder) { - final LLVMValueRef v_left = left.translate(module, builder); - final LLVMValueRef v_right = right.translate(module, builder); - switch (op) { - case PLUS: return LLVMBuildFAdd(builder, v_left, v_right, "addtmp"); - case MINUS: return LLVMBuildFSub(builder, v_left, v_right, "subtmp"); - case TIMES: return LLVMBuildFMul(builder, v_left, v_right, "multmp"); - case DIV: return LLVMBuildFDiv(builder, v_left, v_right, "divtmp"); - default: fatal("unknown operator %s in binary operation", op); - return LLVMConstReal(LLVMDoubleType(), 0); - } - } -} -\end{pygmented} -\end{frame} - - - -\begin{frame}[fragile,allowframebreaks]{Atividade 1} - \begin{tcolorbox}[title=Inverso aditivo] - Implementar a operação que calcula o inverso aditivo (ou negação) - à linguagem \lang{}. Será usado o operador unário prefixo - \pyginline|-|, com precedência maior que dos operadores - aritméticos binários. - \begin{enumerate} - \item Definir uma nova classe \pyginline|absyn.ExpNegate| - \begin{itemize} - \item subclasse de \pyginline|absyn.Exp| - \item contendo um campo correspondente ao operando da negação - \item implementar o método \pyginline|toTree| - \item implementar o método \pyginline|translate| - \end{itemize} - \item Acrescentar uma regra de produção adequada na gramática da - linguagem. - \end{enumerate} - - \begin{tips} - \item Na geração de código use o método - - \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMBuildFNeg-org.bytedeco.javacpp.LLVM.LLVMBuilderRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-java.lang.String-}{\pyginline|LLVMBuildFNeg|} - - \href{http://llvm.org/docs/doxygen/html/group__LLVMCCoreInstructionBuilder.html#gaf748025627b03f4f2659b006b127b758}{\pyginline|LLVMBuildFNeg|} - \end{tips} -\end{tcolorbox} - - \framebreak - - Comandos úteis: -\begin{Verbatim}[frame=single] -$ cd /eplan -$ git checkout master -$ git pull upstream master -$ git checkout -b atividade1 -$ # desenvolva sua atividade -$ # faça testes -$ git status -$ git add -$ git commit -m -$ git push origin atividade1 -$ # faça um pull request no github -\end{Verbatim} -\end{frame} - - -\section{Análise semântica} - -\begin{frame}[fragile,allowframebreaks]{Anotando a localização na árvore sintática} - \begin{itemize} - \item Na análise semêntica os erros encontrados devem ser - reportados. - - \item Deve-se indicar a localização do erro no código fonte. - - \item Por isto a árvore sintática deve conter a - \textbf{localização}. - - \item O atributo \pyginline|loc| foi adicionado à classe abstrata - \pyginline|absyn.AST|. -\begin{pygmented}[] -import parse.Loc; - -public abstract class AST implements ToTree { - - // Location where the phrase was found in the source code - protected final Loc loc; - - public AST(Loc loc) { - this.loc = loc; - } - - // ... -} -\end{pygmented} - - \framebreak - - \item Um argumento correspondente foi adicionado aos construtores - das subclasses de \pyginline|absyn.AST|. Por exemplo: -\begin{pygmented}[] -public class ExpReal extends Exp { - - public final String value; - - public ExpReal(Loc loc, String value) { - super(loc); - this.value = value; - } - - // ... -} -\end{pygmented} - - \framebreak - - \item A criação das árvores sintáticas nas ações semânticas do - analisador sintático deve informar a localização. Exemplo: -\begin{pygmented}[] -factor ::= - LITREAL:x {: RESULT = new ExpReal(loc(xxleft,xxright), x); :} -; -\end{pygmented} - - \item Na regra de produção, ao indicarmos o nome do valor - semântico de um símbolo, são criadas três variáveis no analisador - gerado pelo CUP, contendo as seguintes informações: - \begin{itemize} - \item valor semântico do símbolo - \item posição onde o símbolo começou no código fonte - \item posição onde o símbolo terminou no código fonte - \end{itemize} - No exemplo estas variáveis são respectivamente \pyginline|x|, - \pyginline|xxleft|, e \pyginline|xxright|. - \end{itemize} -\end{frame} - - -\begin{frame}[fragile,allowframebreaks]{Representando os tipos da linguagem} - \begin{itemize} - \item O pacote \pyginline|type| contém classes usadas para representar - os tipos da linguagem sendo compilada. - \item A representação geral é \pyginline|Type|. - \item \pyginline|Type| é uma classe abstrata, com subclasses concretas - para representar cada uma das possibiliades: - \begin{center} - \small - \begin{tabular}{lll} \hline - \textbf{descrição} & \textbf{classe} & \textbf{objeto} \\\hline - \texttt{bool} & \pyginline|BOOL| & \pyginline|BOOL.T| \\ - \texttt{int} & \pyginline|INT| & \pyginline|INT.T| \\ - \texttt{real} & \pyginline|REAL| & \pyginline|REAL.T| \\ - \texttt{char} & \pyginline|CHAR| & \pyginline|CHAR.T| \\ - \texttt{string} & \pyginline|STRING| & \pyginline|STRING.T| \\ - \emph{array} & \pyginline|ARRAY| & \pyginline|new Array(Type element)| \\ - \emph{registro} & \pyginline|RECORD| & \pyginline|new RECORD(List> fields)| \\ - \emph{registro nulo} & \pyginline|NIL| & \pyginline|NIL.T| \\ - \texttt{unit} & \pyginline|UNIT| & \pyginline|UNIT.T| \\ - \emph{nome} & \pyginline|NAME| & \pyginline|new Name(Symbol name, Type binding)| \\\hline - \end{tabular} - \end{center} - \end{itemize} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{Algumas operações com tipos} - \begin{description} - \item[\pyginline|Type actual()|]\mbox{}\newline - \begin{itemize} - \item Retorna a representação que é de fato usada para o tipo. - \item É o próprio objeto, exceto para a classe \pyginline|NAME|, onde - é retornado \pyginline|binding.actual()|. - \end{itemize} - \framebreak - - \item[\pyginline|boolean is(Type type)|]\mbox{}\newline - \begin{itemize} - \item Verifica se o tipo que recebe a mensagem é compatível (é igual - ou pode ser convertido para) o tipo dado como argumento. - \item Retorna \pyginline|true| somente se os dois tipos forem - idênticos, exceto nos seguintes casos: - \begin{itemize} - \item o tipo do registo nulo (\texttt{nil}), \pyginline|NIL|, é - compatível com \pyginline|NIL| e com qualquer tipo registro, - \item um tipo \pyginline|NAME| é compatível com algum tipo, se - e somente se o seu atributo \pyginline|binding| for compatível - com o tipo. - \end{itemize} - \end{itemize} - \framebreak - - \item[\pyginline|boolean is(Type... types)|]\mbox{}\newline - \begin{itemize} - \item Verifica a compatibilidade com algum dos tipos dados como - argumentos. - \end{itemize} - \end{description} -\end{frame} - - -\begin{frame}[fragile,allowframebreaks]{Reportando erros comuns} - \begin{itemize} - \item A interface \pyginline|semantic.SemanticHelper| define - alguns métodos para reportar erros comumente encontrados pelo - compilador no código fonte. - - \item Um dos erros mais comuns é a inconsistência de tipos. -\begin{pygmented}[] -public interface SemanticHelper { - - static CompilerError typeMismatch(Loc loc, Type found, Type... expected) - // ... - } - - // ... -} -\end{pygmented} - \end{itemize} -\end{frame} - -\begin{frame}[fragile,allowframebreaks]{Análise semântica} - \begin{itemize} - \item O analisador semântico - \begin{itemize} - \item verifica a consistência do programa - \item calcula o tipo das expressões - \end{itemize} - \item Expressões tem um atributo \pyginline|type| cujo valor é a - representação do tipo obtido para a expressão. - \item \pyginline|type| é calculado pelo analisador semântico. -\begin{pygmented}[] -import types.Type; - -public abstract class Exp extends AST { - - // Type of the expression, calculated by the semantic analyser - public Type type; - - // Obtain the type of the expression as a string prefixed by the given text. - protected String annotateType(String text) { - final String theType = type == null ? "" : "\n<" + type + ">"; - return text + theType; - } - - // ... -} -\end{pygmented} - - \framebreak - - \item O método \pyginline|semantic| da classe - \pyginline|absyn.Exp| faz análise semântica da expressão. - \begin{itemize} - \item Usa o método auxiliar \pyginline|semantic_| para fazer a - análise semântica de fato, obtendo o tipo da expressão. - \item Coloca o tipo encontrado no atributo \pyginline|type|. - \end{itemize} -\begin{pygmented}[] -public abstract class Exp extends AST { - // ... - - // Do semantic analysis of the expression - public Type semantic() { - type = semantic_(); - return type; - } - - // Type check the expression. Should be defined in the concrete subclasses. - protected abstract Type semantic_(); -} -\end{pygmented} - - \item Subclasses de \pyginline|absyn.Exp| devem definir o método - \pyginline|semantic_| apropriadamente. - - \item Por exemplo: -\begin{pygmented}[] -public class ExpReal extends Exp { - // ... - - @Override - protected Type semantic_() { - return REAL.T; - } -} -\end{pygmented} - - \end{itemize} -\end{frame} - - - -\begin{frame}[fragile,allowframebreaks]{Atividade 2: literal inteiro} - Implementar \textbf{literais inteiros} no compilador de \lang{}. - \begin{enumerate} - \item Para desenvolver esta atividade faça o \emph{checkout} da - \alert{versão 0.17} do projeto. - - \item Definir uma nova classe \pyginline|types.INT| para - representar o tipo \texttt{int} de \lang{}. - - \item Definir uma nova classe \pyginline|absyn.ExpInt| para - representar as árvores sintáticas das constantes inteiras: - \begin{itemize} - \item subclasse de \pyginline|absyn.Exp| - \item contendo um campo correspondente ao valor da constante - \item implementar o método \pyginline|toTree| - \item implementar o método \pyginline|semantic_| - \item implementar o método \pyginline|translate| - \end{itemize} - - \item Modifique a classe \pyginline|absyn.ExpBinOp| de forma que - os operadores aritméticos aceitem operandos inteiros e - reais. Neste momento não é necessário fazer conversão implícita - dos operandos de inteiro para real. Por hora os operandos devem - apenas ser do mesmo tipo numérico. - - \item Acrescentar na gramática da linguagem: - \begin{itemize} - \item o símbolo terminal \pyginline|LITINT| - \item uma regra de produção adequada - \end{itemize} - - \item Na especificação léxica da linguagem - \begin{itemize} - \item acrescentar uma regra para o literal inteiro: - - Um literal inteiro é uma sequência não vazia de dígitos - decimais. - - \item modificar a regra do literal real para não casar com - literais inteiros - \end{itemize} - - \item Definir a função \pyginline|__eplan_print_int| (em C) na - biblioteca padrão de \lang{} para exibir um valor inteiro. O - protótipo da função deve ser: -\begin{pygmented}[] -extern void __eplan_print_int(const int32_t x) -\end{pygmented} - O tipo \pyginline|int32_t| está definido em - \texttt{inttypes.h}. Use a função \pyginline|printf| e a macro - \pyginline|PRIi32| na formatação da saída. - - \item Modificar o método \pyginline|addRuntime| na classe - \pyginline|translate.Generator| para adicionar o protótipo da função - \pyginline|__eplan_print_int| no código gerado. - - \item Modificar o método \pyginline|addPrintResult| na classe - \pyginline|codegen.Generator| para considerar o caso de valores - inteiros. Este método gera código para exibir o valor de uma - expressão na saída padrão. - \end{enumerate} - - \begin{tips} - \item Na geração de código use os métodos - - \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMConstIntOfString-org.bytedeco.javacpp.LLVM.LLVMTypeRef-java.lang.String-byte-}{\pyginline|LLVMConstIntOfString|} - - \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMBuildAdd-org.bytedeco.javacpp.LLVM.LLVMBuilderRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-java.lang.String-}{\pyginline|LLVMBuildAdd|} - - \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMBuildSub-org.bytedeco.javacpp.LLVM.LLVMBuilderRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-java.lang.String-}{\pyginline|LLVMBuildSub|} - - \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMBuildMul-org.bytedeco.javacpp.LLVM.LLVMBuilderRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-java.lang.String-}{\pyginline|LLVMBuildMul|} - - \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMBuildSDiv-org.bytedeco.javacpp.LLVM.LLVMBuilderRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-java.lang.String-}{\pyginline|LLVMBuildSDiv|} -\end{tips} -\end{frame} - - - -% \section{Identificadores} - - -% \begin{frame}[fragile,allowframebreaks]{Representando identificadores} -% \begin{itemize} -% \item \textbf{Identificadores} são nomes dados a diversas entidades em -% um programa: tipos, variáveis, funções, módulos, classes, etc. -% \item Quando uma declaração é analisada, alguma informação sobre o -% identificador é armazenada em um \textbf{ambiente} (um dicionário, -% também chamado de \textbf{tabela de símbolos}), contendo por exemplo: -% \begin{itemize} -% \item tipo de uma variável -% \item tipo dos argumentos e do resultado de uma função -% \item estrutura de um tipo -% \end{itemize} -% \item Posteriormente quando o nome é usado em uma frase, esta informação -% deve ser recuperada do ambiente para analisar a frase. -% \item Poderiam ser representados por \emph{strings}. -% \item Porém \pyginline|String| não é uma boa escolha porque: -% \begin{itemize} -% \item a representação na memória é ineficiente, pois todos os -% caracteres do nome são armazenados repetidamente, uma vez para cada -% ocorrência do nome, e -% \item a pesquisa na tabela de símbolos é ineficiente, pois é baseada -% na comparação de possivelmente todos os caracteres da nome. -% \end{itemize} -% \end{itemize} -% \end{frame} - - -% \begin{frame}[fragile,allowframebreaks]{Símbolos} -% \begin{itemize} -% \item Novo tipo para representar identificadores: -% \pyginline|symbol.Symbol|. -% \item Quando o analisador léxico encontra o nome pela primeira vez, ele -% o armazena na memória. -% \item Nas demais ocorrências do nome o analisador léxico usa uma -% referência para o nome já armazenado na memória. -% \item Desta forma cada nome é alocado na memória uma única vez. -% \item A comparação dos nomes se resume à comparação de referências. -% \item Consegue-se assim uma melhor eficiência no uso da memória, e -% também na comparação de nomes, fundamental para a pesquisa na tabela de -% símbolos. -% \item Um símbolo é construído a partir de uma string usando o método -% \pyginline|symbol.Symbol symbol.Symbol.symbol(String nome)|. -% \end{itemize} -% \end{frame} - -% \begin{frame}[fragile,allowframebreaks]{Há duas classes \texttt{Symbol}} -% \begin{itemize} -% \item \pyginline|java_cup.runtime.Symbol|\newline -% Representam símbolos gramaticais (terminais e não terminais). - -% \item \pyginline|symbol.Symbol|\newline -% Representam identificadores. -% \end{itemize} -% \end{frame} - - -% \begin{frame}[fragile,allowframebreaks]{O problema dos tipos mutuamente recursivos} -% \begin{itemize} -% \item A classe \pyginline|NAME| é usada na compilação de tipos -% mutuamente recursivos. -% \item O tipo é usado na definição de si mesmo ou de outros tipos com -% dependência mútua. -% \item Exemplo: -% \begin{pygmented}[lang=text] -% let type list = { head: tree, tail: list } -% type tree = { info: int, children: list } -% in -% # ... -% \end{pygmented} -% \item Problema: ao pesquisar a ocorrência do tipo que aparece no lado -% direito da definição, ele ainda não se encontra na tabela de símbolos -% (pois está sendo compilado neste momento), gerando um erro de \emph{tipo -% indefinido}. -% \item Solução: compilação em duas etapas: -% \begin{itemize} -% \item Primeiramente é criada e inserida na tabela de símbolos uma -% instância de \pyginline|NAME| para representar o tipo. -% \item Posteriormente compila-se a definição do tipo e atualiza-se o -% atributo \pyginline|binding| deste objeto. -% \end{itemize} -% \end{itemize} -% \end{frame} - - -% \begin{frame}[fragile,allowframebreaks]{Ambiente (Tabelas de Símbolos)} -% \begin{itemize} -% \item O \textbf{ambiente} é formado por \textbf{tabelas de símbolos} -% (\textbf{dicionários} cuja chave é um símbolo). -% \item Contém informações sobre os identificadores válidos em um -% determinado ponto do programa sendo compilado: -% \begin{itemize} -% \item \textbf{variáveis}: tipo da variável -% \item \textbf{funções}: tipo dos argumentos e tipo do resultado da -% função -% \item \textbf{tipos}: estrutura do tipo -% \end{itemize} -% \item Implementação: classe \pyginline|env.Env| -% \item Há dois espaços de nomes, implementados em duas tabelas de -% símbolos: -% \begin{itemize} -% \item \textbf{variáveis e funções}: atributo \pyginline|venv|\newline -% A cada símbolo é associado uma instância da classe abstrata -% \pyginline|env.Entry|, que tem duas classes concretas: -% \begin{itemize} -% \item \pyginline|env.VarEntry(Type ty)| -% \item \pyginline|env.FunEntry(Type result, List formals)| -% \end{itemize} -% \item \textbf{tipos}: atributo \pyginline|tenv|\newline A cada símbolo -% é associado uma instância da classe abstrata \pyginline|type.Type|. -% \end{itemize} -% \end{itemize} -% \begin{center} -% \small -% \begin{tabular}{lll}\hline -% \textbf{espaço de nomes} & \textbf{atributo} & \textbf{informação associada ao símbolo} \\\hline -% variáveis e funções & \pyginline|venv| & \pyginline|Entry| \\ -% & & ~\pyginline|VarEntry(Type ty)| \\ -% & & ~\pyginline|FunEntry(Type result, List formals)| \\\hline -% tipos & \pyginline|tenv| & \pyginline|Type| \\\hline -% \end{tabular} -% \end{center} -% \end{frame} - - -% \begin{frame}[fragile,allowframebreaks]{Nomes pré-definidos} -% \begin{itemize} -% \item O construtor da classe \pyginline|Env| deve criar as tabelas de -% símbolos e incluir os nomes pré-definidos da linguagem (biblioteca -% padrão). - -% \item Tipos: -% \begin{pygmented}[lang=text] -% bool -% int -% real -% char -% string -% unit -% \end{pygmented} - -% \item Variáveis: não há nenhuma variável pré-definida. -% \framebreak - -% \item Funções: -% \begin{pygmented}[lang=text] -% function print_bool(x: bool): unit -% function not(b: bool): bool - -% function print_int(x: int): unit - -% function print_real(x: real): unit -% function round(f: real): int -% function ceil(f: real): int -% function floor(f: real): int -% function real(i: int): real - -% function print(x: string): unit -% function length(s: string): int -% function substring(s: string, start: int, length: int): string -% \end{pygmented} -% \end{itemize} -% \end{frame} - - - -% \begin{frame}[fragile,allowframebreaks]{Variáveis simples} -% \begin{center} -% \begin{synshorts} -% \small -% \begin{tabular}{r@{$\;\rightarrow\;$}l>{\textcolor{blue}\bgroup}r<{\egroup}} -% & & variável \\ -% & ":=" & atribuição \\ -% & "let" "in" & expressão de declaração \\[.9em] -% & "id" & variável simples \\[.9em] -% & & sequência de declarações \\ -% & & \\[.9em] -% & "var" "id" ":" "id" "=" & declaração de variável \\ -% & "var" "id" "=" & \\ -% \end{tabular} -% \end{synshorts -% } -% \end{center} -% \end{frame} - -% \begin{frame}[fragile,allowframebreaks]{Variáveis simples: árvores sintáticas} -% \begin{pygmented}[] -% // declarações -% Dec(Loc loc) // classe abstrata -% VarDec(Loc loc, Symbol name, Symbol type, Exp init) - -% // variáveis -% Var(Loc loc) // classe abstrata -% SimpleVar(Loc loc, Symbol name) - -% // expressões -% LetExp(Loc loc, List decs, Exp body) -% VarExp(Loc loc, Var var) -% AssignExp(Loc loc, Var var, Exp exp) -% \end{pygmented} -% \end{frame} - -\begin{frame} - \begin{center} - Fim - - % \texttt{Fim} - - % \texttt{\textbf{Fim}} - - % \textbf{\texttt{Fim}} - - % {This is big!} - - % {\smaller[3] This is big!} - \end{center} -\end{frame} - -\end{document} - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: t -%%% End: +\documentclass[smaller]{beamer} + +\usepackage{iftex} + +\RequireLuaTeX + +\usepackage[]{fontspec} +\usepackage[brazilian]{babel} + +\usepackage{dirtree} +\usepackage{tikz-qtree} +\usepackage{syntax} +\usepackage{pygmentex} +% \usepackage{jrmmisc} +\usepackage{tcolorbox} +\usepackage{relsize} +\usepackage{indentfirst} + +% \setmainfont{Times New Roman} +% \setsansfont[Scale=MatchLowercase]{Helvetica} +% \setmonofont[Scale=MatchLowercase]{Courier} + +% \setmainfont{Times New Roman} +% \setsansfont[Scale=MatchLowercase]{Helvetica LT Std} +% \setmonofont[Scale=MatchLowercase]{Courier Std} + +% \setmainfont{DejaVu Serif} +% \setsansfont[Scale=MatchLowercase]{DejaVu Sans} +% \setmonofont[Scale=MatchLowercase]{DejaVu Sans Mono} + +\setmainfont{Liberation Serif} +\setsansfont[Scale=MatchLowercase]{Liberation Sans} +\setmonofont[Scale=MatchLowercase]{Liberation Mono} + +% \setmainfont{Lucida Std} +% \setsansfont[Scale=MatchLowercase]{Lucida Sans Std} +% \setmonofont[Scale=MatchLowercase]{Lucida Sans Typewriter Std} +% % \setmonofont[Scale=MatchLowercase]{Lucida Typewriter Std} + +% \setmainfont{Luxi Serif} +% \setsansfont[Scale=MatchLowercase]{Luxi Sans} +% \setmonofont[Scale=MatchLowercase]{Luxi Mono} + +% \setmainfont{Nimbus Roman No9 L} +% \setsansfont[Scale=MatchLowercase]{Nimbus Sans L} +% \setmonofont[Scale=MatchLowercase]{Nimbus Mono L} + +% \setmainfont{Droid Serif} +% \setsansfont[Scale=MatchLowercase]{Droid Sans} +% \setmonofont[Scale=MatchLowercase]{Droid Sans Mono} % no bold + +% \setmonofont[Scale=MatchLowercase]{Anonymous Pro} +% \setmonofont[Scale=MatchLowercase]{Consolas} +% \setmonofont[Scale=MatchLowercase]{Courier New} +% \setmonofont[Scale=MatchLowercase]{Cousine} +% \setmonofont[Scale=MatchLowercase]{DejaVu Sans Mono} +% \setmonofont[Scale=MatchLowercase]{Fantasque Sans Mono} +% \setmonofont[Scale=MatchLowercase]{Fira Code} +% \setmonofont[Scale=MatchLowercase]{Fira Mono} +% \setmonofont[Scale=MatchLowercase]{FreeMono} +% \setmonofont[Scale=MatchLowercase]{Hack} +% \setmonofont[Scale=MatchLowercase]{Input Mono Condensed} +% \setmonofont[Scale=MatchLowercase]{Iosevka Slab} +% \setmonofont[Scale=MatchLowercase]{Iosevka} +% \setmonofont[Scale=MatchLowercase]{Liberation Mono} +% \setmonofont[Scale=MatchLowercase]{Noto Mono} +% \setmonofont[Scale=MatchLowercase]{Source Code Pro} +% \setmonofont[Scale=MatchLowercase]{SF Mono} +% \setmonofont[Scale=MatchLowercase]{Ubuntu Mono} +\setmonofont[Scale=MatchLowercase]{M+ 1m} +% % +% \setmonofont[Scale=MatchLowercase]{Letter Gothic Std} +% \setmonofont[Scale=MatchLowercase]{Lucida Sans Typewriter Std} +% \setmonofont[Scale=MatchLowercase]{Luxi Mono} + + +\setbeamercovered{transparent} +\hypersetup{colorlinks} +\usetheme{OuroPreto} + +\newenvironment{tips}{% + \textbf{Dicas:}\newline + \begin{list}{*}{% + \setlength{\topsep}{0pt}% + \setlength{\itemsep}{0pt}% + \setlength{\parsep}{0pt}% + }% + }{% + \end{list}% +} + +\usetikzlibrary{ + calc, + shapes.multipart, + chains, + arrows, + graphs, + graphdrawing, +} + +\usegdlibrary{ + layered +} + +\tikzset{ + joined/.style = { + join=by ->, + }, + cons/.style = { + draw, + rounded corners, + rectangle split, + rectangle split parts=2, + rectangle split horizontal, + joined, + }, + var/.style = { + blue, + joined, + }, + null/.style = { + fill, + circle, + inner sep=0mm, + minimum size=2mm, + joined, + }, +} + +\renewcommand{\DTcomment}[1]{\textcolor{yellow}{\hrulefill}\sffamily\textcolor{blue}{#1}} +% \renewcommand\DTstylecomment{\sffamily\color{green}\textsc} +\renewcommand\DTstyle{\ttfamily\textcolor{red}} +\setlength{\DTbaselineskip}{12pt} + +\newcommand{\semester}{2016.2} + +\newcommand{\lang}{\textsl{EPLan}} + + +\setpygmented{lang=java,tabsize=3,sty=default} +\efboxsetup{hidealllines,backgroundcolor=yellow!28} + +\mdfsetup{ + % backgroundcolor=green!10, + roundcorner=2pt, + skipabove=2pt, + skipbelow=2pt, + innerleftmargin=2pt, + innerrightmargin=2pt, + innertopmargin=.25\baselineskip, + innerbottommargin=.25\baselineskip, +} + + +% syntax configuration +\renewcommand{\syntleft}{\normalfont\slshape\hspace{0.25em}} +\renewcommand{\syntright}{\hspace{0.25em}} +\renewcommand{\ulitleft}{\normalfont\ttfamily\bfseries\frenchspacing\color{red}\hspace{0.25em}} +\renewcommand{\ulitright}{\hspace{0.25em}} + + + + +\begin{document} + +\title[compiler]{ + Compilador de \lang{} +} +\subject{Linguagens de Programação} +\author{José Romildo Malaquias} +\institute[UFOP]{ + Departamento de Computação\\ + Universidade Federal de Ouro Preto +} +\date{\semester} + +\frame{\titlepage} + +\frame{\tableofcontents} + + +\section{A estrutura do compilador} + + +\begin{frame}{Organização do compilador} + \begin{itemize} + \item Implementado na linguagem \textbf{Java}. + \item Ferramentas auxiliares: + \begin{itemize} + \item \textbf{JFlex}: gerador de analisador léxico + \item \textbf{CUP}: gerador de analisador sintático + \item \textbf{LLVM}: gerador de código + \item \textbf{Maven}: ferramenta de automação de compilação de + projetos Java + \end{itemize} + \item Usa bibliotecas externas: + \begin{itemize} + \item \textbf{commons-lang3}: complementa as classes que estão + em \pyginline|java.lang|. + + \item \textbf{jcommander}: framework Java muito pequeno que + torna trivial a análise de parâmetros de linha de comando + + \item \textbf{javacpp-presets-llvm}: interface para a biblioteca + LLVMC do projeto LLVM (infraestrutura de construçào de + compilador escrita em C++) + + \item \textbf{javaslang}: uma biblioteca funcional para Java 8+ que + fornece tipos de dados persistentes e estruturas de controle + funcionais + + \item \textbf{javaslang-render}: biblioteca de renderização para + algumas estruturas de dados fornecidas por javaslang + + \item \textbf{junit}: \emph{framework} com suporte à criação de testes + automatizados em Java + + \item \textbf{assertj}: fornece um rico conjunto de afirmações, com + mensagens de erro úteis, melhorando a legibilidade dos testes + automatizados em Java + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}[fragile]{Maven} + \begin{itemize} + \item Usado para automatizar a compilação de projetos. + \item O projeto é configurado usando um \textbf{POM} (\emph{Project + Object Model)}, que é armazenado em um arquivo \texttt{pom.xml}. + \item O desenvolvimento pode ser feito em várias \textbf{fases}, + indicadas por \textbf{objetivos}, como: + \begin{center} + \begin{tabular}{ll} + \textit{clean} & remover arquivos gerados \\ + \textit{generate-sources} & gerar código automático \\ + \textit{process-resources} & processar recursos \\ + \textit{compile} & compilar \\ + \textit{process-test-resources} & processar recursos de teste \\ + \textit{test-compile} & testar compilação \\ + \textit{test} & testar \\ + \textit{package} & empacotar \\ + \textit{install} & instalar \\ + \textit{deploy} & implantar + \end{tabular} + \end{center} + \item Exemplo: compilar o projeto na linha de comando: +\begin{Verbatim}[frame=single] +$ mvn compile +\end{Verbatim} + \end{itemize} +\end{frame} + +\begin{frame}{Estrutura de diretórios do projeto} + \small + \noindent + \dirtree{% + .1 \lang{}-compiler. + .2 src\DTcomment{código fonte do projeto}. + .3 main\DTcomment{código fonte principal}. + .4 c\DTcomment{código fonte em C}. + .4 cup\DTcomment{código fonte para o CUP}. + .4 java\DTcomment{código fonte em Java}. + .4 jflex\DTcomment{código fonte para o JFlex}. + .3 test\DTcomment{código fonte dos testes}. + .4 java\DTcomment{código fonte dos testes em Java}. + .2 target\DTcomment{arquivos gerados automaticamente}. + .3 classes\DTcomment{classes geradas pelo compilador de Java}. + .3 generated-sources\DTcomment{código fonte gerado por ferramentas}. + .4 cup\DTcomment{código fonte gerado pelo CUP}. + .4 jflex\DTcomment{código fonte gerado pelo JFlex}. + .3 generated-test-sources\DTcomment{cód. fonte de testes gerado por ferramentas}. + .3 test-classes\DTcomment{classes dos testes geradas pelo compilador de Java}. + .2 pom.xml\DTcomment{arquivo de especificação do projeto}. + } +\end{frame} + +\section{Javaslang} + +\begin{frame}[fragile,allowframebreaks]{Javaslang} + \begin{itemize} + \item Javaslang fornece várias estruturas de dados funcionais, como: + \begin{itemize} + \item tuplas + \item listas + \item árvores + \begin{itemize} + \item Árvores serão amplamente utilizadas para exibir as + estruturas internas do compilador, incluindo as árvores + sintáticas. + \end{itemize} + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.Tuple2}} + \footnotesize +\begin{pygmented}[] +import javaslang.Tuple; +import javaslang.Tuple2; + +public class TestJavaslang { + public static void main(String[] args) { + Tuple2 person = Tuple.of("paul", 17); + + String name = person._1; + Integer age = person._2; + + Tuple2 p = + person.map(n -> n + " jones", + a -> a + 1); + + Tuple2 q = + person.map((n, a) -> Tuple.of(n + " jones", a + 1)); + + String s = person.transform((n, a) -> n + ": " + a); + + System.out.println(s); + } +} +\end{pygmented} +\end{frame} + + + +\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.collection.List}} + \begin{itemize} + \item Exemplos de listas (simplesmente) encadeadas: +\begin{pygmented}[] +List list1 = List.empty(); +List list2 = List.of("nice"); +List list3 = List.of(11, 12, 13); +List list4 = list3.tail(); +List list5 = list4.prepend(10); +\end{pygmented} + \begin{center} + \begin{tikzpicture}[ + cons/.style={draw}, + var/.style={draw=none,blue}, + null/.style={circle,inner sep=0mm,minimum size=1mm}, + ] + + \graph [ + %layered layout, + grow right sep, + nodes={cons}, + ] { + list1[var] -> n1[null,as={}]; + list2[var] -> nice -> n2[null,as={}]; + list3[var] -> 11 -> 12 -> 13 -> n3[null,as={}]; + list4[var] -> 12; + list5[var] -> 10 -> 12; + }; + + \end{tikzpicture} + \end{center} + + \framebreak + + \item Operando com cada elemento de uma lista: +\begin{pygmented}[] +List lst = List.of(10, 20, 30); + +for (Integer x : lst) + System.out.println(x); + +lst.forEach(x -> System.out.println(x)); + +lst.forEach(System.out::println); +\end{pygmented} + + \framebreak + + \item Aplicando uma função a cada elemento da lista e coletando os + resultados em outra lista: +\begin{pygmented}[] +List a = List.of(4.0, 9.0, 25.0); +List c = a.map(Math::sqrt); +List b = a.map(x -> 2*x); +\end{pygmented} + + \framebreak + + \item Reduzindo uma lista: +\begin{pygmented}[] +List a = List.of("1", "2", "3"); +String str = a.fold("", (a1, a2) -> a1 + a2); + +List b = List.of(1, 2, 3, 4); +Integer sum = b.fold(0, (s, x) -> s + x); +\end{pygmented} + + \end{itemize} +\end{frame} + + + + +\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.collection.Tree}} +\begin{pygmented}[] +Tree tree1 = Tree.empty(); +Tree tree2 = Tree.of("nice"); +Tree tree3 = Tree.of(99, 21, 22, 23); +Tree tree4 = Tree.of(10, + Tree.of(5, Tree.of(2)), + Tree.of(7), + Tree.of(0), + Tree.of(19, Tree.of(3), Tree.of(8))); +\end{pygmented} + \begin{center} + \begin{tikzpicture}[ + cons/.style={draw}, + var/.style={draw=none,blue}, + null/.style={circle,inner sep=0mm,minimum size=1mm}, + ] + + \graph [ + layered layout, + %grow right sep, + nodes={cons}, + ] { + tree1[var] -> n1[null,as={}]; + tree2[var] -> nice; + tree3[var] -> 99 -> {21, 22, 23}; + tree4[var] -> 10 -> {5 -> 2, 7, 0, 19 -> {3, 8}}; + }; + + \end{tikzpicture} + \end{center} +\end{frame} + + +\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.render.text.PrettyPrinter}} + \small + \begin{columns}[t] + \begin{column}{.75\textwidth} +\begin{pygmented}[] +import javaslang.collection.Tree; + +import javaslang.render.text.PrettyPrinter; + +final Tree tree = + Tree.of("Ann", + Tree.of("Mary", + Tree.of("John", + Tree.of("Avila")), + Tree.of("Karen", + Tree.of("Frank")), + Tree.of("Steven\nAbbot\nBraddock")), + Tree.of("Peter", + Tree.of("Paul\nPalucci"), + Tree.of("Anthony")), + Tree.of("Christopher", + Tree.of("Samuel"))); + +final String out = PrettyPrinter.pp(tree); +\end{pygmented} + \end{column} + \begin{column}{.25\textwidth} +\begin{Verbatim} +Ann +├──Mary +│ ├──John +│ │ └──Avila +│ ├──Karen +│ │ └──Frank +│ └──Steven +│ Abbot +│ Braddock +├──Peter +│ ├──Paul +│ │ Palucci +│ └──Anthony +└──Christopher + └──Samuel +\end{Verbatim} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.render.text.Boxes}} + \footnotesize +\begin{pygmented}[] +import javaslang.collection.Tree; +import javaslang.render.text.Boxes; + +final Tree tree = /* ... */ + +final String out = Boxes.box(tree).toString(); +\end{pygmented} + +\begin{verbatim} + ┌───┐ + │Ann│ + └─┬─┘ + ┌───────────────┴──────┬────────────────┐ + ┌──┴─┐ ┌──┴──┐ ┌─────┴─────┐ + │Mary│ │Peter│ │Christopher│ + └──┬─┘ └──┬──┘ └─────┬─────┘ + ┌───────┬─┴───────┐ ┌────┴────┐ │ +┌──┴─┐ ┌──┴──┐ ┌────┴───┐ ┌───┴───┐ ┌───┴───┐ ┌───┴──┐ +│John│ │Karen│ │ Steven │ │ Paul │ │Anthony│ │Samuel│ +└──┬─┘ └──┬──┘ │ Abbot │ │Palucci│ └───────┘ └──────┘ + │ │ │Braddock│ └───────┘ +┌──┴──┐ ┌──┴──┐ └────────┘ +│Avila│ │Frank│ +└─────┘ └─────┘ +\end{verbatim} +\end{frame} + + +\begin{frame}[fragile,allowframebreaks]{\texttt{javaslang.render.text.DotFile}} + \small + \begin{columns}[t] + \begin{column}{.5\textwidth} +\begin{pygmented}[] +import javaslang.collection.Tree; +import javaslang.render.dot.DotFile; + +final Tree tree = /* ... */; + +DotFile.write(tree, "tree.dot"); +\end{pygmented} + \end{column} + \begin{column}{.5\textwidth} + \begin{itemize} + \item Dot é uma linguagem para descrever grafos. + \item É necessário o pacote \textbf{graphviz}. + \end{itemize} +\begin{Verbatim}[frame=single] +$ dot -Tpng -O tree.dot +\end{Verbatim} + \end{column} + \end{columns} + \begin{center} + \makebox[0pt][r]{\texttt{tree.dot.png}} + \includegraphics[scale=.35]{images/tree.png} + \end{center} +\end{frame} + +\section{Posição no código fonte} + +\begin{frame}[fragile,allowframebreaks]{Localização no código fonte} + \begin{itemize} + \item A localização é usada para reportar erros. + \item Indica onde uma frase do programa começa e termina no código + fonte. + \item Representada pela classe \pyginline|parse.Loc| + \begin{pygmented}[lang=java] +Loc(Location left, Location right) + \end{pygmented} + \item Usa o tipo + \begin{pygmented}[lang=java] +java_cup.runtime.ComplexSymbolFactory.Location + \end{pygmented} + contendo informações como: + \begin{itemize} + \item nome da unidade de compilação (arquivo fonte) + \item número da linha + \item número da coluna + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{Construção da localização} + \begin{itemize} + \item Alguns métodos de fábrica: +\begin{pygmented}[] +import java_cup.runtime.Symbol; +import java_cup.runtime.ComplexSymbolFactory.ComplexSymbol; +import java_cup.runtime.ComplexSymbolFactory.Location; + +/* ... */ + +public static Loc loc() +public static Loc loc(Location left) +public static Loc loc(Location left, Location right) +public static Loc loc(Symbol symbol) +public static Loc loc(Symbol a, Symbol b) +public static Loc loc(ComplexSymbol symbol) +public static Loc loc(ComplexSymbol a, ComplexSymbol b) +\end{pygmented} + + \item \pyginline|Symbol| e \pyginline|ComplexSymbol| representam + símbolos terminais + \end{itemize} +\end{frame} + + +\section{Gerenciamento de erros} + +\begin{frame}[fragile,allowframebreaks]{Reportagem de erro} + \begin{itemize} + \item Os erros são reportados por meio do mecanismo de + \textbf{exceções} de Java. + \item Erros no programa fonte são representados pela classe + \pyginline|error.CompileError|, subclasse de + \pyginline|RuntimeError|. + \item Erros na implementação do compilador são representados pela + classe \pyginline|error.FatalError|, também subclasse de + \pyginline|RuntimeError|. + \item A classe \pyginline|error.ErrorHelper| tem alguns métodos + estáticos que facilitam a criação de objetos de erro: +\begin{pygmented}[] +static CompilerError error(String message) +static CompilerError error(String format, Object... args) +static CompilerError error(Loc loc, String format, Object... args) + +static FatalError fatal(String format, Object... args) +\end{pygmented} + \end{itemize} +\end{frame} + + +\section{Análise léxica} + +\begin{frame}[fragile,allowframebreaks]{Símbolos terminais} + \begin{itemize} + \item Os \textbf{símbolos terminais} são definidos na gramática + livre de contexto do CUP (arquivo + \texttt{src/main/cup/parser.cup}). + \item Exemplos: +\begin{pygmented}[] +terminal String LITREAL; +terminal PLUS, MINUS, TIMES, DIV; +terminal LPAREN, RPAREN; +\end{pygmented} + + \item O CUP gera uma interface \pyginline|parse.SymbolConstants| + contendo a definição de constantes correspondentes aos terminais + que foram declarados. + + \item Quando relevante os terminais podem ter um valor semântico + associado. + + \item A classe \pyginline|ComplexSymbol| é usada para representar + os símbolos terminais, contendo as seguintes informações: + \begin{itemize} + \item classificação (como declarado na gramática) + \item lexema + \item localização (começo e fim) no código fonte + \item valor semântico + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{Regras léxicas} + \begin{itemize} + \item O analisador léxico é gerado pelo \textbf{JFlex}. + \item As regras léxicas são especificadas no arquivo + \alert{\texttt{src/main/jflex/lexer.jflex}}. + \item O JFlex cria a classe \pyginline|parse.Lexer| compatível com + o CUP. + \item Os \textbf{lexemas} (palavras que formam os símbolos + léxicos) são descritos por \textbf{expressões regulares}. + \item A classificação so símbolo terminal é feita na \textbf{ação + semântica} (código em Java que faz parte da regra léxica). + \item Para facilitar a criação dos diversos símbolos léxicos + recomenda-se o uso dos \alert{métodos auxiliares} (definidos no + próprio arquivo de especificação): +\begin{pygmented}[] +private Symbol tok(int type, String lexeme, Object value) +private Symbol tok(int type, Object value) +private Symbol tok(int type) +\end{pygmented} + \end{itemize} +\end{frame} + + +\begin{frame}[fragile,allowframebreaks]{Exemplo de regras léxicas} +\begin{pygmented}[lang=text] +[ \t\f\n\r]+ { /* skip */ } + +[0-9]+ ("." [0-9]+)? { return tok(LITREAL, yytext()); } + +"+" { return tok(PLUS); } +"-" { return tok(MINUS); } +"*" { return tok(TIMES); } +"/" { return tok(DIV); } +"(" { return tok(LPAREN); } +")" { return tok(RPAREN); } + +. { throw error(Loc.loc(locLeft()), + "unexpected char '%s'", + yytext()); } +\end{pygmented} +\end{frame} + + +\section{Análise sintática} + +\begin{frame}[fragile,allowframebreaks]{Análise sintática} + \begin{itemize} + \item A especificação sintática (\textbf{gramática livre de + contexto}) é feita no arquivo + \alert{\texttt{src/main/cup/parser.cup}}. + \item Algumas opções de execução do CUP são indicadas no arquivo + \alert{\texttt{pom.xml}}. + \item O analisador sintático é gerado pelo \textbf{CUP}, que cria + a classe \pyginline|parse.Parser| e a interface + \pyginline|parse.SymbolConstants|. + \item Na gramática livre de contexto são especificados: + \begin{itemize} + \item os símbolos terminais + \item os símbols não terminais + \item o símbolo inicial + \item as regras de produção + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{Ações semânticas} + \begin{itemize} + \item Quando um símbolo (terminal ou não terminal) tem um + \textbf{valor semântico}, o tipo do valor semântico é informado na + declaração do símbolo. + \item O cálculo do valor semântico do símbolo no lado esquerdo de + uma regra de produção é feito usando os valores semênticas dos + símbolos que aparecem no lado direiro da regra através de uma + \textbf{ação semântica} (código em Java). + \item Quando um \alert{nome} é associado a um símbolo no lado + direito de uma regra (por exemplo \pyginline|exp:nome|), o CUP + cria três variáveis (no exemplo \pyginline|nome|, + \pyginline|nomexleft| e \pyginline|nomexright|) no codigo gerado, + contendo o valor semântico, a localização esquerda (onde começa no + código fonte), e a localização direita (onde termina no código + fonte) do símbolo, respectivamente. + \end{itemize} +\end{frame} + + +\begin{frame}[fragile,allowframebreaks]{Exemplo de gramática para o CUP} + \scriptsize +\begin{pygmented}[] +terminal String LITREAL; +terminal PLUS, MINUS, TIMES, DIV; +terminal LPAREN, RPAREN; + +non terminal Exp exp; +non terminal Exp term; +non terminal Exp factor; + +start with exp; + +exp ::= + exp:x PLUS term:y {: RESULT = new ExpBinOp(ExpBinOp.Op.PLUS, x, y); :} +| exp:x MINUS term:y {: RESULT = new ExpBinOp(ExpBinOp.Op.MINUS, x, y); :} +| term:x {: RESULT = x; :} +; + +term ::= +| term:x TIMES factor:y {: RESULT = new ExpBinOp(ExpBinOp.Op.TIMES, x, y); :} +| term:x DIV factor:y {: RESULT = new ExpBinOp(ExpBinOp.Op.DIV, x, y); :} +| factor:x {: RESULT = x; :} +; + +factor ::= + LITREAL:x {: RESULT = new ExpReal(x); :} +| LPAREN exp:x RPAREN {: RESULT = x; :} +; +\end{pygmented} +\end{frame} + + +\section{Árvores sintáticas} + +\begin{frame}[fragile,allowframebreaks]{Árvores sintáticas} + \begin{itemize} + \item \textbf{Árvore sintática} é uma \alert{estrutura de dados + hierárquica} que representa a estrutura sintática do programa + fonte. + \item A \textbf{raiz} da árvore é o \alert{símbolo inicial} da + gramática. + \item As \textbf{folhas} são os \alert{símbolos terminais} que, + lidos da esquerda para a direita, correspondem ao programa fonte. + \item Pode ser: + \begin{itemize} + \item \textbf{concreta}: todos os símbolos na sequência de + derivação são colocados na árvore + \item \textbf{abstrata}: apenas as informações relevantes para o + entendimento da estrutura do programa são mantidos na árvore + \end{itemize} + \item A saída do \textbf{analisador sintático} é uma árvore + sintática abstrata (\alert{AST}). + \end{itemize} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{Representação} + \begin{itemize} + \item A representação das árvores sintáticas é feita através de + classes no pacote \pyginline|absyn|. + \item A classe abstrata \pyginline|absyn.AST| é superclasse de + todas as árvores sintáticas abstratas. + \item Esta classe implementa a interface \pyginline|ToTree|: +\begin{pygmented}[] +package javaslang.render; + +import javaslang.collection.Tree; + +public interface ToTree { + public abstract Tree.Node toTree(); +} +\end{pygmented} + \item O método \pyginline|toTree| converte a árvore abstrata em + uma estrutura de dados geral para árvores cujos nós armazenam + strings, útil na apresentação visual da árvore sintática. + \end{itemize} +\end{frame} + + +\begin{frame}[fragile,allowframebreaks]{Definindo as árvores abstratas} + \begin{itemize} + \item Para cada \alert{categoria sintática} (como expressões, + comandos, ou declarações) reprentada por um \textbf{símbolo não + terminal} definimos uma subclasse abstrata de + \pyginline|absyn.AST|. + \item Para cada \alert{forma} da categoria sintática para um não + terminal (como as formas de expressão: expressão constante, + operação binária, chamada de função, etc.), representada por uma + \textbf{regra de produção}, definamos uma subclasse da classe que + representa aquela forma específica da categoria sintática. + \item + Nesta classe deve-se: + \begin{itemize} + \item definir os \alert{campos} necessários para os componentes + (sub-árvores) da árvore sintática, + \item definir \alert{construtores} que inicializam estes campos + com valores passados como argumentos, + \item definir o método \pyginline|toTree|. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{A classe AST} +\begin{pygmented}[] +package absyn; + +import javaslang.render.ToTree; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +public abstract class AST implements ToTree { + + @Override + public String toString() { + return ToStringBuilder.reflectionToString( + this, + ToStringStyle.SHORT_PREFIX_STYLE); + } + +} +\end{pygmented} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{A classe Exp} +\begin{pygmented}[] +package absyn; + +public abstract class Exp extends AST { +} +\end{pygmented} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{A classe ExpReal} +\begin{pygmented}[] +package absyn; + +import javaslang.collection.Tree; + +public class ExpReal extends Exp { + + public final String value; + + public ExpReal(String value) { + this.value = value; + } + + @Override + public Tree.Node toTree() { + return Tree.of("ExpReal: " + value); + } +} +\end{pygmented} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{A classe ExpReal} + \relscale{0.78} +\begin{pygmented}[] +package absyn; + +import javaslang.collection.Tree; + +public class ExpBinOp extends Exp { + + public enum Op {PLUS, MINUS, TIMES, DIV} + + public final Op op; + public final Exp left; + public final Exp right; + + public ExpBinOp(Op op, Exp left, Exp right) { + this.op = op; + this.left = left; + this.right = right; + } + + @Override + public Tree.Node toTree() { + return Tree.of("ExpBinOp: " + op, left.toTree(), right.toTree()); + } +} +\end{pygmented} +\end{frame} + + +\section{Geração de código} + +\begin{frame}[fragile,allowframebreaks]{Representação intermediária} + \begin{itemize} + \item A árvore sintática do programa fonte é traduzida para uma + representação intermediária do código fonte. + \item Usaremos a representação intermediária do framework + \textbf{LLVM}. + \item A biblioteca Java \texttt{javacpp-presets-llvm} será usada + para criar a representação intermediária. + \item A classe \pyginline|absyn.Exp| deve ter um método abstrato + para converter uma expressão para a sua representação + intermediária. +\begin{pygmented}[] +import static org.bytedeco.javacpp.LLVM.*; +/* ... */ +public abstract LLVMValueRef translate(LLVMModuleRef module, + LLVMBuilderRef builder); +\end{pygmented} + \item Suas subclasses devem implementar este método. + \end{itemize} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{Representação intermediária de constantes} +\begin{pygmented}[] +package absyn; + +// ... +import static org.bytedeco.javacpp.LLVM.*; + +public class ExpReal extends Exp { + // ... + + @Override + public LLVMValueRef translate(LLVMModuleRef module, + LLVMBuilderRef builder) { + return LLVMConstRealOfString(LLVMDoubleType(), value); + } +} +\end{pygmented} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{Representação intermediária de operação binária} + \relscale{0.76} +\begin{pygmented}[] +package absyn; + +// ... +import static org.bytedeco.javacpp.LLVM.*; +import static error.ErrorHelper.fatal; + +public class ExpBinOp extends Exp { + // ... + + @Override + public LLVMValueRef translate(LLVMModuleRef module, LLVMBuilderRef builder) { + final LLVMValueRef v_left = left.translate(module, builder); + final LLVMValueRef v_right = right.translate(module, builder); + switch (op) { + case PLUS: return LLVMBuildFAdd(builder, v_left, v_right, "addtmp"); + case MINUS: return LLVMBuildFSub(builder, v_left, v_right, "subtmp"); + case TIMES: return LLVMBuildFMul(builder, v_left, v_right, "multmp"); + case DIV: return LLVMBuildFDiv(builder, v_left, v_right, "divtmp"); + default: fatal("unknown operator %s in binary operation", op); + return LLVMConstReal(LLVMDoubleType(), 0); + } + } +} +\end{pygmented} +\end{frame} + + + +\begin{frame}[fragile,allowframebreaks]{Atividade 1} + \begin{tcolorbox}[title=Inverso aditivo] + Implementar a operação que calcula o inverso aditivo (ou negação) + à linguagem \lang{}. Será usado o operador unário prefixo + \pyginline|-|, com precedência maior que dos operadores + aritméticos binários. + \begin{enumerate} + \item Definir uma nova classe \pyginline|absyn.ExpNegate| + \begin{itemize} + \item subclasse de \pyginline|absyn.Exp| + \item contendo um campo correspondente ao operando da negação + \item implementar o método \pyginline|toTree| + \item implementar o método \pyginline|translate| + \end{itemize} + \item Acrescentar uma regra de produção adequada na gramática da + linguagem. + \end{enumerate} + + \begin{tips} + \item Na geração de código use o método + + \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMBuildFNeg-org.bytedeco.javacpp.LLVM.LLVMBuilderRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-java.lang.String-}{\pyginline|LLVMBuildFNeg|} + + \href{http://llvm.org/docs/doxygen/html/group__LLVMCCoreInstructionBuilder.html#gaf748025627b03f4f2659b006b127b758}{\pyginline|LLVMBuildFNeg|} + \end{tips} +\end{tcolorbox} + + \framebreak + + Comandos úteis: +\begin{Verbatim}[frame=single] +$ cd /eplan +$ git checkout master +$ git pull upstream master +$ git checkout -b atividade1 +$ # desenvolva sua atividade +$ # faça testes +$ git status +$ git add +$ git commit -m +$ git push origin atividade1 +$ # faça um pull request no github +\end{Verbatim} +\end{frame} + + +\section{Análise semântica} + +\begin{frame}[fragile,allowframebreaks]{Anotando a localização na árvore sintática} + \begin{itemize} + \item Na análise semêntica os erros encontrados devem ser + reportados. + + \item Deve-se indicar a localização do erro no código fonte. + + \item Por isto a árvore sintática deve conter a + \textbf{localização}. + + \item O atributo \pyginline|loc| foi adicionado à classe abstrata + \pyginline|absyn.AST|. +\begin{pygmented}[] +import parse.Loc; + +public abstract class AST implements ToTree { + + // Location where the phrase was found in the source code + protected final Loc loc; + + public AST(Loc loc) { + this.loc = loc; + } + + // ... +} +\end{pygmented} + + \framebreak + + \item Um argumento correspondente foi adicionado aos construtores + das subclasses de \pyginline|absyn.AST|. Por exemplo: +\begin{pygmented}[] +public class ExpReal extends Exp { + + public final String value; + + public ExpReal(Loc loc, String value) { + super(loc); + this.value = value; + } + + // ... +} +\end{pygmented} + + \framebreak + + \item A criação das árvores sintáticas nas ações semânticas do + analisador sintático deve informar a localização. Exemplo: +\begin{pygmented}[] +factor ::= + LITREAL:x {: RESULT = new ExpReal(loc(xxleft,xxright), x); :} +; +\end{pygmented} + + \item Na regra de produção, ao indicarmos o nome do valor + semântico de um símbolo, são criadas três variáveis no analisador + gerado pelo CUP, contendo as seguintes informações: + \begin{itemize} + \item valor semântico do símbolo + \item posição onde o símbolo começou no código fonte + \item posição onde o símbolo terminou no código fonte + \end{itemize} + No exemplo estas variáveis são respectivamente \pyginline|x|, + \pyginline|xxleft|, e \pyginline|xxright|. + \end{itemize} +\end{frame} + + +\begin{frame}[fragile,allowframebreaks]{Representando os tipos da linguagem} + \begin{itemize} + \item O pacote \pyginline|type| contém classes usadas para representar + os tipos da linguagem sendo compilada. + \item A representação geral é \pyginline|Type|. + \item \pyginline|Type| é uma classe abstrata, com subclasses concretas + para representar cada uma das possibiliades: + \begin{center} + \small + \begin{tabular}{lll} \hline + \textbf{descrição} & \textbf{classe} & \textbf{objeto} \\\hline + \texttt{bool} & \pyginline|BOOL| & \pyginline|BOOL.T| \\ + \texttt{int} & \pyginline|INT| & \pyginline|INT.T| \\ + \texttt{real} & \pyginline|REAL| & \pyginline|REAL.T| \\ + \texttt{char} & \pyginline|CHAR| & \pyginline|CHAR.T| \\ + \texttt{string} & \pyginline|STRING| & \pyginline|STRING.T| \\ + \emph{array} & \pyginline|ARRAY| & \pyginline|new Array(Type element)| \\ + \emph{registro} & \pyginline|RECORD| & \pyginline|new RECORD(List> fields)| \\ + \emph{registro nulo} & \pyginline|NIL| & \pyginline|NIL.T| \\ + \texttt{unit} & \pyginline|UNIT| & \pyginline|UNIT.T| \\ + \emph{nome} & \pyginline|NAME| & \pyginline|new Name(Symbol name, Type binding)| \\\hline + \end{tabular} + \end{center} + \end{itemize} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{Algumas operações com tipos} + \begin{description} + \item[\pyginline|Type actual()|]\mbox{}\newline + \begin{itemize} + \item Retorna a representação que é de fato usada para o tipo. + \item É o próprio objeto, exceto para a classe \pyginline|NAME|, onde + é retornado \pyginline|binding.actual()|. + \end{itemize} + \framebreak + + \item[\pyginline|boolean is(Type type)|]\mbox{}\newline + \begin{itemize} + \item Verifica se o tipo que recebe a mensagem é compatível (é igual + ou pode ser convertido para) o tipo dado como argumento. + \item Retorna \pyginline|true| somente se os dois tipos forem + idênticos, exceto nos seguintes casos: + \begin{itemize} + \item o tipo do registo nulo (\texttt{nil}), \pyginline|NIL|, é + compatível com \pyginline|NIL| e com qualquer tipo registro, + \item um tipo \pyginline|NAME| é compatível com algum tipo, se + e somente se o seu atributo \pyginline|binding| for compatível + com o tipo. + \end{itemize} + \end{itemize} + \framebreak + + \item[\pyginline|boolean is(Type... types)|]\mbox{}\newline + \begin{itemize} + \item Verifica a compatibilidade com algum dos tipos dados como + argumentos. + \end{itemize} + \end{description} +\end{frame} + + +\begin{frame}[fragile,allowframebreaks]{Reportando erros comuns} + \begin{itemize} + \item A interface \pyginline|semantic.SemanticHelper| define + alguns métodos para reportar erros comumente encontrados pelo + compilador no código fonte. + + \item Um dos erros mais comuns é a inconsistência de tipos. +\begin{pygmented}[] +public interface SemanticHelper { + + static CompilerError typeMismatch(Loc loc, Type found, Type... expected) + // ... + } + + // ... +} +\end{pygmented} + \end{itemize} +\end{frame} + +\begin{frame}[fragile,allowframebreaks]{Análise semântica} + \begin{itemize} + \item O analisador semântico + \begin{itemize} + \item verifica a consistência do programa + \item calcula o tipo das expressões + \end{itemize} + \item Expressões tem um atributo \pyginline|type| cujo valor é a + representação do tipo obtido para a expressão. + \item \pyginline|type| é calculado pelo analisador semântico. +\begin{pygmented}[] +import types.Type; + +public abstract class Exp extends AST { + + // Type of the expression, calculated by the semantic analyser + public Type type; + + // Obtain the type of the expression as a string prefixed by the given text. + protected String annotateType(String text) { + final String theType = type == null ? "" : "\n<" + type + ">"; + return text + theType; + } + + // ... +} +\end{pygmented} + + \framebreak + + \item O método \pyginline|semantic| da classe + \pyginline|absyn.Exp| faz análise semântica da expressão. + \begin{itemize} + \item Usa o método auxiliar \pyginline|semantic_| para fazer a + análise semântica de fato, obtendo o tipo da expressão. + \item Coloca o tipo encontrado no atributo \pyginline|type|. + \end{itemize} +\begin{pygmented}[] +public abstract class Exp extends AST { + // ... + + // Do semantic analysis of the expression + public Type semantic() { + type = semantic_(); + return type; + } + + // Type check the expression. Should be defined in the concrete subclasses. + protected abstract Type semantic_(); +} +\end{pygmented} + + \item Subclasses de \pyginline|absyn.Exp| devem definir o método + \pyginline|semantic_| apropriadamente. + + \item Por exemplo: +\begin{pygmented}[] +public class ExpReal extends Exp { + // ... + + @Override + protected Type semantic_() { + return REAL.T; + } +} +\end{pygmented} + + \end{itemize} +\end{frame} + + + +\begin{frame}[fragile,allowframebreaks]{Atividade 2: literal inteiro} + Implementar \textbf{literais inteiros} no compilador de \lang{}. + \begin{enumerate} + \item Para desenvolver esta atividade faça o \emph{checkout} da + \alert{versão 0.17} do projeto. + + \item Definir uma nova classe \pyginline|types.INT| para + representar o tipo \texttt{int} de \lang{}. + + \item Definir uma nova classe \pyginline|absyn.ExpInt| para + representar as árvores sintáticas das constantes inteiras: + \begin{itemize} + \item subclasse de \pyginline|absyn.Exp| + \item contendo um campo correspondente ao valor da constante + \item implementar o método \pyginline|toTree| + \item implementar o método \pyginline|semantic_| + \item implementar o método \pyginline|translate| + \end{itemize} + + \item Modifique a classe \pyginline|absyn.ExpBinOp| de forma que + os operadores aritméticos aceitem operandos inteiros e + reais. Neste momento não é necessário fazer conversão implícita + dos operandos de inteiro para real. Por hora os operandos devem + apenas ser do mesmo tipo numérico. + + \item Acrescentar na gramática da linguagem: + \begin{itemize} + \item o símbolo terminal \pyginline|LITINT| + \item uma regra de produção adequada + \end{itemize} + + \item Na especificação léxica da linguagem + \begin{itemize} + \item acrescentar uma regra para o literal inteiro: + + Um literal inteiro é uma sequência não vazia de dígitos + decimais. + + \item modificar a regra do literal real para não casar com + literais inteiros + \end{itemize} + + \item Definir a função \pyginline|__eplan_print_int| (em C) na + biblioteca padrão de \lang{} para exibir um valor inteiro. O + protótipo da função deve ser: +\begin{pygmented}[] +extern void __eplan_print_int(const int32_t x) +\end{pygmented} + O tipo \pyginline|int32_t| está definido em + \texttt{inttypes.h}. Use a função \pyginline|printf| e a macro + \pyginline|PRIi32| na formatação da saída. + + \item Modificar o método \pyginline|addRuntime| na classe + \pyginline|translate.Generator| para adicionar o protótipo da função + \pyginline|__eplan_print_int| no código gerado. + + \item Modificar o método \pyginline|addPrintResult| na classe + \pyginline|codegen.Generator| para considerar o caso de valores + inteiros. Este método gera código para exibir o valor de uma + expressão na saída padrão. + \end{enumerate} + + \begin{tips} + \item Na geração de código use os métodos + + \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMConstIntOfString-org.bytedeco.javacpp.LLVM.LLVMTypeRef-java.lang.String-byte-}{\pyginline|LLVMConstIntOfString|} + + \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMBuildAdd-org.bytedeco.javacpp.LLVM.LLVMBuilderRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-java.lang.String-}{\pyginline|LLVMBuildAdd|} + + \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMBuildSub-org.bytedeco.javacpp.LLVM.LLVMBuilderRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-java.lang.String-}{\pyginline|LLVMBuildSub|} + + \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMBuildMul-org.bytedeco.javacpp.LLVM.LLVMBuilderRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-java.lang.String-}{\pyginline|LLVMBuildMul|} + + \href{http://bytedeco.org/javacpp-presets/llvm/apidocs/org/bytedeco/javacpp/LLVM.html#LLVMBuildSDiv-org.bytedeco.javacpp.LLVM.LLVMBuilderRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-org.bytedeco.javacpp.LLVM.LLVMValueRef-java.lang.String-}{\pyginline|LLVMBuildSDiv|} +\end{tips} +\end{frame} + + + +% \section{Identificadores} + + +% \begin{frame}[fragile,allowframebreaks]{Representando identificadores} +% \begin{itemize} +% \item \textbf{Identificadores} são nomes dados a diversas entidades em +% um programa: tipos, variáveis, funções, módulos, classes, etc. +% \item Quando uma declaração é analisada, alguma informação sobre o +% identificador é armazenada em um \textbf{ambiente} (um dicionário, +% também chamado de \textbf{tabela de símbolos}), contendo por exemplo: +% \begin{itemize} +% \item tipo de uma variável +% \item tipo dos argumentos e do resultado de uma função +% \item estrutura de um tipo +% \end{itemize} +% \item Posteriormente quando o nome é usado em uma frase, esta informação +% deve ser recuperada do ambiente para analisar a frase. +% \item Poderiam ser representados por \emph{strings}. +% \item Porém \pyginline|String| não é uma boa escolha porque: +% \begin{itemize} +% \item a representação na memória é ineficiente, pois todos os +% caracteres do nome são armazenados repetidamente, uma vez para cada +% ocorrência do nome, e +% \item a pesquisa na tabela de símbolos é ineficiente, pois é baseada +% na comparação de possivelmente todos os caracteres da nome. +% \end{itemize} +% \end{itemize} +% \end{frame} + + +% \begin{frame}[fragile,allowframebreaks]{Símbolos} +% \begin{itemize} +% \item Novo tipo para representar identificadores: +% \pyginline|symbol.Symbol|. +% \item Quando o analisador léxico encontra o nome pela primeira vez, ele +% o armazena na memória. +% \item Nas demais ocorrências do nome o analisador léxico usa uma +% referência para o nome já armazenado na memória. +% \item Desta forma cada nome é alocado na memória uma única vez. +% \item A comparação dos nomes se resume à comparação de referências. +% \item Consegue-se assim uma melhor eficiência no uso da memória, e +% também na comparação de nomes, fundamental para a pesquisa na tabela de +% símbolos. +% \item Um símbolo é construído a partir de uma string usando o método +% \pyginline|symbol.Symbol symbol.Symbol.symbol(String nome)|. +% \end{itemize} +% \end{frame} + +% \begin{frame}[fragile,allowframebreaks]{Há duas classes \texttt{Symbol}} +% \begin{itemize} +% \item \pyginline|java_cup.runtime.Symbol|\newline +% Representam símbolos gramaticais (terminais e não terminais). + +% \item \pyginline|symbol.Symbol|\newline +% Representam identificadores. +% \end{itemize} +% \end{frame} + + +% \begin{frame}[fragile,allowframebreaks]{O problema dos tipos mutuamente recursivos} +% \begin{itemize} +% \item A classe \pyginline|NAME| é usada na compilação de tipos +% mutuamente recursivos. +% \item O tipo é usado na definição de si mesmo ou de outros tipos com +% dependência mútua. +% \item Exemplo: +% \begin{pygmented}[lang=text] +% let type list = { head: tree, tail: list } +% type tree = { info: int, children: list } +% in +% # ... +% \end{pygmented} +% \item Problema: ao pesquisar a ocorrência do tipo que aparece no lado +% direito da definição, ele ainda não se encontra na tabela de símbolos +% (pois está sendo compilado neste momento), gerando um erro de \emph{tipo +% indefinido}. +% \item Solução: compilação em duas etapas: +% \begin{itemize} +% \item Primeiramente é criada e inserida na tabela de símbolos uma +% instância de \pyginline|NAME| para representar o tipo. +% \item Posteriormente compila-se a definição do tipo e atualiza-se o +% atributo \pyginline|binding| deste objeto. +% \end{itemize} +% \end{itemize} +% \end{frame} + + +% \begin{frame}[fragile,allowframebreaks]{Ambiente (Tabelas de Símbolos)} +% \begin{itemize} +% \item O \textbf{ambiente} é formado por \textbf{tabelas de símbolos} +% (\textbf{dicionários} cuja chave é um símbolo). +% \item Contém informações sobre os identificadores válidos em um +% determinado ponto do programa sendo compilado: +% \begin{itemize} +% \item \textbf{variáveis}: tipo da variável +% \item \textbf{funções}: tipo dos argumentos e tipo do resultado da +% função +% \item \textbf{tipos}: estrutura do tipo +% \end{itemize} +% \item Implementação: classe \pyginline|env.Env| +% \item Há dois espaços de nomes, implementados em duas tabelas de +% símbolos: +% \begin{itemize} +% \item \textbf{variáveis e funções}: atributo \pyginline|venv|\newline +% A cada símbolo é associado uma instância da classe abstrata +% \pyginline|env.Entry|, que tem duas classes concretas: +% \begin{itemize} +% \item \pyginline|env.VarEntry(Type ty)| +% \item \pyginline|env.FunEntry(Type result, List formals)| +% \end{itemize} +% \item \textbf{tipos}: atributo \pyginline|tenv|\newline A cada símbolo +% é associado uma instância da classe abstrata \pyginline|type.Type|. +% \end{itemize} +% \end{itemize} +% \begin{center} +% \small +% \begin{tabular}{lll}\hline +% \textbf{espaço de nomes} & \textbf{atributo} & \textbf{informação associada ao símbolo} \\\hline +% variáveis e funções & \pyginline|venv| & \pyginline|Entry| \\ +% & & ~\pyginline|VarEntry(Type ty)| \\ +% & & ~\pyginline|FunEntry(Type result, List formals)| \\\hline +% tipos & \pyginline|tenv| & \pyginline|Type| \\\hline +% \end{tabular} +% \end{center} +% \end{frame} + + +% \begin{frame}[fragile,allowframebreaks]{Nomes pré-definidos} +% \begin{itemize} +% \item O construtor da classe \pyginline|Env| deve criar as tabelas de +% símbolos e incluir os nomes pré-definidos da linguagem (biblioteca +% padrão). + +% \item Tipos: +% \begin{pygmented}[lang=text] +% bool +% int +% real +% char +% string +% unit +% \end{pygmented} + +% \item Variáveis: não há nenhuma variável pré-definida. +% \framebreak + +% \item Funções: +% \begin{pygmented}[lang=text] +% function print_bool(x: bool): unit +% function not(b: bool): bool + +% function print_int(x: int): unit + +% function print_real(x: real): unit +% function round(f: real): int +% function ceil(f: real): int +% function floor(f: real): int +% function real(i: int): real + +% function print(x: string): unit +% function length(s: string): int +% function substring(s: string, start: int, length: int): string +% \end{pygmented} +% \end{itemize} +% \end{frame} + + + +% \begin{frame}[fragile,allowframebreaks]{Variáveis simples} +% \begin{center} +% \begin{synshorts} +% \small +% \begin{tabular}{r@{$\;\rightarrow\;$}l>{\textcolor{blue}\bgroup}r<{\egroup}} +% & & variável \\ +% & ":=" & atribuição \\ +% & "let" "in" & expressão de declaração \\[.9em] +% & "id" & variável simples \\[.9em] +% & & sequência de declarações \\ +% & & \\[.9em] +% & "var" "id" ":" "id" "=" & declaração de variável \\ +% & "var" "id" "=" & \\ +% \end{tabular} +% \end{synshorts +% } +% \end{center} +% \end{frame} + +% \begin{frame}[fragile,allowframebreaks]{Variáveis simples: árvores sintáticas} +% \begin{pygmented}[] +% // declarações +% Dec(Loc loc) // classe abstrata +% VarDec(Loc loc, Symbol name, Symbol type, Exp init) + +% // variáveis +% Var(Loc loc) // classe abstrata +% SimpleVar(Loc loc, Symbol name) + +% // expressões +% LetExp(Loc loc, List decs, Exp body) +% VarExp(Loc loc, Var var) +% AssignExp(Loc loc, Var var, Exp exp) +% \end{pygmented} +% \end{frame} + +\begin{frame} + \begin{center} + Fim + + % \texttt{Fim} + + % \texttt{\textbf{Fim}} + + % \textbf{\texttt{Fim}} + + % {This is big!} + + % {\smaller[3] This is big!} + \end{center} +\end{frame} + +\end{document} + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: t +%%% End: diff --git a/doc/images/tree.dot b/doc/images/tree.dot index 66bca33..8f39de1 100644 --- a/doc/images/tree.dot +++ b/doc/images/tree.dot @@ -1,22 +1,22 @@ -digraph tree { - lbl8 [label="Anthony"]; - lbl6 [label="Peter"]; - lbl7 [label="Paul -Palucci"]; - lbl0 [label="Ann"]; - lbl1 [label="Mary"]; - lbl4 [label="Karen"]; - lbl5 [label="Steven -Abbot -Braddock"]; - lbl2 [label="John"]; - lbl3 [label="Avila"]; - lbl0 -> lbl1; - lbl1 -> lbl2; - lbl2 -> lbl3; - lbl1 -> lbl4; - lbl1 -> lbl5; - lbl0 -> lbl6; - lbl6 -> lbl7; - lbl6 -> lbl8; -} +digraph tree { + lbl8 [label="Anthony"]; + lbl6 [label="Peter"]; + lbl7 [label="Paul +Palucci"]; + lbl0 [label="Ann"]; + lbl1 [label="Mary"]; + lbl4 [label="Karen"]; + lbl5 [label="Steven +Abbot +Braddock"]; + lbl2 [label="John"]; + lbl3 [label="Avila"]; + lbl0 -> lbl1; + lbl1 -> lbl2; + lbl2 -> lbl3; + lbl1 -> lbl4; + lbl1 -> lbl5; + lbl0 -> lbl6; + lbl6 -> lbl7; + lbl6 -> lbl8; +} diff --git a/driver b/driver index 39eb0fb..ccefc87 100755 --- a/driver +++ b/driver @@ -1,12 +1,12 @@ -#! /bin/sh - -if [ -x nixos-version ]; then - if nixos-version &>/dev/null; then - export LD_LIBRARY_PATH=/nix/store/2vcyb5n74xh8c97rb6pnr25cdyav9x0f-gcc-5.4.0/lib64 - fi -fi - -# export LC_NUMERIC=en_US-UTF-8 - -exec java -jar target/uber-eplan-0.1-SNAPSHOT.jar $@ - +#! /bin/sh + +if [ -x nixos-version ]; then + if nixos-version &>/dev/null; then + export LD_LIBRARY_PATH=/nix/store/2vcyb5n74xh8c97rb6pnr25cdyav9x0f-gcc-5.4.0/lib64 + fi +fi + +# export LC_NUMERIC=en_US-UTF-8 + +exec java -jar target/uber-eplan-0.1-SNAPSHOT.jar $@ + diff --git a/pom.xml b/pom.xml index a16fbbb..41dd4b9 100644 --- a/pom.xml +++ b/pom.xml @@ -1,145 +1,145 @@ - - 4.0.0 - - br.ufop.decom.bcc328 - eplan - 0.1-SNAPSHOT - jar - - EPlan compiler - https://github.com/romildo/eplan - - - UTF-8 - 1.8 - 1.8 - - - - - com.beust - jcommander - 1.58 - - - - com.github.vbmacher - java-cup-runtime - 11b-20160615 - - - - org.apache.commons - commons-lang3 - 3.5 - - - - io.javaslang - javaslang - 2.0.5 - - - - io.javaslang - javaslang-render - 2.0.0 - - - - junit - junit - 4.12 - test - - - - org.assertj - assertj-core - 3.6.2 - test - - - - - - - de.jflex - jflex-maven-plugin - 1.6.1 - - - - generate - - - - - - - com.github.vbmacher - cup-maven-plugin - 11b-20160615 - - - - generate - - - - - parse - Parser - SymbolConstants - true - - true - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.0.2 - - - - main.Driver - - - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.0.0 - - - package - - shade - - - - - - main.Driver - - - - - - - uber-${project.artifactId}-${project.version} - - - - - - - + + 4.0.0 + + br.ufop.decom.bcc328 + eplan + 0.1-SNAPSHOT + jar + + EPlan compiler + https://github.com/romildo/eplan + + + UTF-8 + 1.8 + 1.8 + + + + + com.beust + jcommander + 1.58 + + + + com.github.vbmacher + java-cup-runtime + 11b-20160615 + + + + org.apache.commons + commons-lang3 + 3.5 + + + + io.javaslang + javaslang + 2.0.5 + + + + io.javaslang + javaslang-render + 2.0.0 + + + + junit + junit + 4.12 + test + + + + org.assertj + assertj-core + 3.6.2 + test + + + + + + + de.jflex + jflex-maven-plugin + 1.6.1 + + + + generate + + + + + + + com.github.vbmacher + cup-maven-plugin + 11b-20160615 + + + + generate + + + + + parse + Parser + SymbolConstants + true + + true + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + + main.Driver + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.0.0 + + + package + + shade + + + + + + main.Driver + + + + + + + uber-${project.artifactId}-${project.version} + + + + + + + diff --git a/run b/run index 95d3b41..99acc9a 100755 --- a/run +++ b/run @@ -1,21 +1,21 @@ -#! /bin/sh - -F=unknown -IMGVIEWER=eog - -if command -v which >/dev/null 2>&1; then - rlwrap ./driver --box-annotated-ast --dot-annotated-ast $@ -else - ./driver $@ -fi || exit $? - -if command -v dot >/dev/null 2>&1; then - echo "Generating image of AST" - echo "-------------------------------------------------" - dot -O -Tpng $F.annotated.dot - if command -v $IMGVIEWER >/dev/null 2>&1; then - echo "View image of AST" - echo "-------------------------------------------------" - $IMGVIEWER $F.annotated.dot.png &> /dev/null - fi -fi +#! /bin/sh + +F=unknown +IMGVIEWER=eog + +if command -v which >/dev/null 2>&1; then + rlwrap ./driver --box-annotated-ast --dot-annotated-ast $@ +else + ./driver $@ +fi || exit $? + +if command -v dot >/dev/null 2>&1; then + echo "Generating image of AST" + echo "-------------------------------------------------" + dot -O -Tpng $F.annotated.dot + if command -v $IMGVIEWER >/dev/null 2>&1; then + echo "View image of AST" + echo "-------------------------------------------------" + $IMGVIEWER $F.annotated.dot.png &> /dev/null + fi +fi diff --git a/src/main/cup/parser.cup b/src/main/cup/parser.cup index ef83e71..d4d55b0 100644 --- a/src/main/cup/parser.cup +++ b/src/main/cup/parser.cup @@ -1,121 +1,123 @@ -package parse; - -import error.ErrorHelper; -import java_cup.runtime.Symbol; -import java_cup.runtime.ComplexSymbolFactory.ComplexSymbol; -import javaslang.collection.List; -import absyn.*; - -parser code {: - public Parser(Lexer lex) { - this(lex, lex.getSymbolFactory()); - } - - private Loc loc(Location left, Location right) { - return Loc.loc(left, right); - } - - /* override error routines */ - private Loc locOfInfo(Object info) { - return info instanceof ComplexSymbol ? - Loc.loc((ComplexSymbol) info) : - info instanceof Symbol ? - Loc.loc((Symbol) info) : - Loc.loc(cur_token); - } - private String lexemeOfInfo(Object info) { - return info instanceof ComplexSymbol ? - " at '" + ((ComplexSymbol) info).getName() + "'" : - ""; - - } - public void report_fatal_error(String message, Object info) { - done_parsing(); - throw ErrorHelper.error(locOfInfo(info), "%s%s%nCan't recover from previous error(s), giving up.", message, lexemeOfInfo(info)); - } - public void report_error(String message, Object info) { - throw ErrorHelper.error(locOfInfo(info), "%s%s", message, lexemeOfInfo(info)); - } -:}; - -terminal String LITINT; -terminal String LITREAL; -terminal String LITBOOL; -terminal String ID; -terminal PLUS, MINUS, TIMES, DIV, UMINUS; -terminal AND, OR; -terminal LPAREN, RPAREN; -terminal COMMA, SEMICOLON; -terminal VAR, EQ, COLON; -terminal LET, IN; - -non terminal Exp program; -non terminal Exp exp; -non terminal List exps, expsRest; -non terminal List expseq, expseqRest; -non terminal Dec dec; -non terminal List decs; -non terminal Var var; - -precedence left OR; -precedence left AND; -precedence left PLUS, MINUS; -precedence left TIMES, DIV; -precedence left UMINUS; - -start with program; - -program ::= - exp:e {: RESULT = e; :} -; - -exp ::= - exp:x PLUS exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.PLUS, x, y); :} -| exp:x MINUS exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.MINUS, x, y); :} -| exp:x TIMES exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.TIMES, x, y); :} -| exp:x DIV exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.DIV, x, y); :} -| exp:x AND exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.AND, x, y); :} -| exp:x OR exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.OR, x, y); :} -| LITINT:x {: RESULT = new ExpInt(loc(xxleft,xxright), x); :} -| LITREAL:x {: RESULT = new ExpReal(loc(xxleft,xxright), x); :} -| LITBOOL:x {: RESULT = new ExpBool(loc(xxleft,xxright), x); :} -| MINUS:m exp:x {: RESULT = new ExpNegate(loc(mxleft,xxright), x); :} %prec UMINUS -| ID:f LPAREN exps:x RPAREN:r {: RESULT = new ExpCall(loc(fxleft,rxright), f, x); :} -| var:v {: RESULT = new ExpVar(loc(vxleft,vxright), v); :} -| LET:l decs:ds IN exp:b {: RESULT = new ExpLet(loc(lxleft,bxright), ds, b); :} -| LPAREN:l expseq:es RPAREN:r {: RESULT = new ExpSeq(loc(lxleft,rxright), es); :} -; - -exps ::= - /* empty */ {: RESULT = List.empty(); :} -| exp:x expsRest:xs {: RESULT = xs.prepend(x); :} -; - -expsRest ::= - /* empty */ {: RESULT = List.empty(); :} -| COMMA exp:x expsRest:xs {: RESULT = xs.prepend(x); :} -; - -expseq ::= - /* empty */ {: RESULT = List.empty(); :} -| exp:x expseqRest:xs {: RESULT = xs.prepend(x); :} -; - -expseqRest ::= - /* empty */ {: RESULT = List.empty(); :} -| SEMICOLON exp:x expseqRest:xs {: RESULT = xs.prepend(x); :} -; - -dec ::= - VAR:v ID:x COLON ID:t EQ exp:e {: RESULT = new DecVar(loc(vxleft,exright), x, t, e); :} -| VAR:v ID:x EQ exp:e {: RESULT = new DecVar(loc(vxleft,exright), x, null, e); :} -; - -decs ::= - dec:x {: RESULT = List.of(x); :} -| dec:x decs:xs {: RESULT = xs.prepend(x); :} -; - -var ::= - ID:v {: RESULT = new VarSimple(loc(vxleft,vxright), v); :} -; +package parse; + +import error.ErrorHelper; +import java_cup.runtime.Symbol; +import java_cup.runtime.ComplexSymbolFactory.ComplexSymbol; +import javaslang.collection.List; +import absyn.*; + +parser code {: + public Parser(Lexer lex) { + this(lex, lex.getSymbolFactory()); + } + + private Loc loc(Location left, Location right) { + return Loc.loc(left, right); + } + + /* override error routines */ + private Loc locOfInfo(Object info) { + return info instanceof ComplexSymbol ? + Loc.loc((ComplexSymbol) info) : + info instanceof Symbol ? + Loc.loc((Symbol) info) : + Loc.loc(cur_token); + } + private String lexemeOfInfo(Object info) { + return info instanceof ComplexSymbol ? + " at '" + ((ComplexSymbol) info).getName() + "'" : + ""; + + } + public void report_fatal_error(String message, Object info) { + done_parsing(); + throw ErrorHelper.error(locOfInfo(info), "%s%s%nCan't recover from previous error(s), giving up.", message, lexemeOfInfo(info)); + } + public void report_error(String message, Object info) { + throw ErrorHelper.error(locOfInfo(info), "%s%s", message, lexemeOfInfo(info)); + } +:}; + +terminal String LITINT; +terminal String LITREAL; +terminal String LITBOOL; +terminal String ID; +terminal PLUS, MINUS, TIMES, DIV, UMINUS; +terminal AND, OR; +terminal LPAREN, RPAREN; +terminal COMMA, SEMICOLON; +terminal VAR, EQ, COLON; +terminal LET, IN; +terminal ASSIGN; + +non terminal Exp program; +non terminal Exp exp; +non terminal List exps, expsRest; +non terminal List expseq, expseqRest; +non terminal Dec dec; +non terminal List decs; +non terminal Var var; + +precedence left OR; +precedence left AND; +precedence left PLUS, MINUS; +precedence left TIMES, DIV; +precedence left UMINUS; + +start with program; + +program ::= + exp:e {: RESULT = e; :} +; + +exp ::= + exp:x PLUS exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.PLUS, x, y); :} +| exp:x MINUS exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.MINUS, x, y); :} +| exp:x TIMES exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.TIMES, x, y); :} +| exp:x DIV exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.DIV, x, y); :} +| exp:x AND exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.AND, x, y); :} +| exp:x OR exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.OR, x, y); :} +| LITINT:x {: RESULT = new ExpInt(loc(xxleft,xxright), x); :} +| LITREAL:x {: RESULT = new ExpReal(loc(xxleft,xxright), x); :} +| LITBOOL:x {: RESULT = new ExpBool(loc(xxleft,xxright), x); :} +| MINUS:m exp:x {: RESULT = new ExpNegate(loc(mxleft,xxright), x); :} %prec UMINUS +| ID:f LPAREN exps:x RPAREN:r {: RESULT = new ExpCall(loc(fxleft,rxright), f, x); :} +| var:v ASSIGN exp:y {: RESULT = new ExpAssign(loc(vxleft,yxright), v, y); :} +| var:v {: RESULT = new ExpVar(loc(vxleft,vxright), v); :} +| LET:l decs:ds IN exp:b {: RESULT = new ExpLet(loc(lxleft,bxright), ds, b); :} +| LPAREN:l expseq:es RPAREN:r {: RESULT = new ExpSeq(loc(lxleft,rxright), es); :} +; + +exps ::= + /* empty */ {: RESULT = List.empty(); :} +| exp:x expsRest:xs {: RESULT = xs.prepend(x); :} +; + +expsRest ::= + /* empty */ {: RESULT = List.empty(); :} +| COMMA exp:x expsRest:xs {: RESULT = xs.prepend(x); :} +; + +expseq ::= + /* empty */ {: RESULT = List.empty(); :} +| exp:x expseqRest:xs {: RESULT = xs.prepend(x); :} +; + +expseqRest ::= + /* empty */ {: RESULT = List.empty(); :} +| SEMICOLON exp:x expseqRest:xs {: RESULT = xs.prepend(x); :} +; + +dec ::= + VAR:v ID:x COLON ID:t EQ exp:e {: RESULT = new DecVar(loc(vxleft,exright), x, t, e); :} +| VAR:v ID:x EQ exp:e {: RESULT = new DecVar(loc(vxleft,exright), x, null, e); :} +; + +decs ::= + dec:x {: RESULT = List.of(x); :} +| dec:x decs:xs {: RESULT = xs.prepend(x); :} +; + +var ::= + ID:v {: RESULT = new VarSimple(loc(vxleft,vxright), v); :} +; diff --git a/src/main/java/absyn/AST.java b/src/main/java/absyn/AST.java index 4663cb6..d5acab2 100644 --- a/src/main/java/absyn/AST.java +++ b/src/main/java/absyn/AST.java @@ -1,22 +1,22 @@ -package absyn; - -import javaslang.render.ToTree; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import parse.Loc; - -public abstract class AST implements ToTree { - - // Location where the phrase was found in the source code - protected final Loc loc; - - public AST(Loc loc) { - this.loc = loc; - } - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); - } - -} +package absyn; + +import javaslang.render.ToTree; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import parse.Loc; + +public abstract class AST implements ToTree { + + // Location where the phrase was found in the source code + protected final Loc loc; + + public AST(Loc loc) { + this.loc = loc; + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); + } + +} diff --git a/src/main/java/absyn/Dec.java b/src/main/java/absyn/Dec.java index f29bb85..75aecc2 100644 --- a/src/main/java/absyn/Dec.java +++ b/src/main/java/absyn/Dec.java @@ -1,16 +1,16 @@ -package absyn; - -import env.Env; -import parse.Loc; -import types.Type; - -public abstract class Dec extends AST { - - public Dec(Loc loc) { - super(loc); - } - - // Do semantic analysis of the declaraction - public abstract void semantic(Env env); - -} +package absyn; + +import env.Env; +import parse.Loc; +import types.Type; + +public abstract class Dec extends AST { + + public Dec(Loc loc) { + super(loc); + } + + // Do semantic analysis of the declaraction + public abstract void semantic(Env env); + +} diff --git a/src/main/java/absyn/DecVar.java b/src/main/java/absyn/DecVar.java index aff4870..d64db72 100644 --- a/src/main/java/absyn/DecVar.java +++ b/src/main/java/absyn/DecVar.java @@ -1,46 +1,46 @@ -package absyn; - -import env.Env; -import javaslang.collection.List; -import javaslang.collection.Tree; -import parse.Loc; -import semantic.SemanticHelper; -import types.Type; - -public class DecVar extends Dec { - - public final String name; - public final String typeName; - public final Exp init; - - public DecVar(Loc loc, String name, String typeName, Exp init) { - super(loc); - this.name = name; - this.typeName = typeName; - this.init = init; - } - - @Override - public Tree.Node toTree() { - List> children = List.of(Tree.of(name)); - if (typeName != null) - children = children.append(Tree.of(typeName)); - children = children.append(init.toTree()); - return Tree.of("DecVar", children); - } - - @Override - public void semantic(Env env) { - Type t_init = init.semantic(env); - Type t_var = t_init; - if (typeName != null) { - Type t_typeName = env.tenv.get(typeName); - if (t_typeName == null) - throw SemanticHelper.undefined(loc, "type", typeName); - if (!t_init.is(t_typeName)) - throw SemanticHelper.typeMismatch(init.loc, t_init, t_typeName); - t_var = t_typeName; - } - env.venv.put(name, t_var); - } -} +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import parse.Loc; +import semantic.SemanticHelper; +import types.Type; + +public class DecVar extends Dec { + + public final String name; + public final String typeName; + public final Exp init; + + public DecVar(Loc loc, String name, String typeName, Exp init) { + super(loc); + this.name = name; + this.typeName = typeName; + this.init = init; + } + + @Override + public Tree.Node toTree() { + List> children = List.of(Tree.of(name)); + if (typeName != null) + children = children.append(Tree.of(typeName)); + children = children.append(init.toTree()); + return Tree.of("DecVar", children); + } + + @Override + public void semantic(Env env) { + Type t_init = init.semantic(env); + Type t_var = t_init; + if (typeName != null) { + Type t_typeName = env.tenv.get(typeName); + if (t_typeName == null) + throw SemanticHelper.undefined(loc, "type", typeName); + if (!t_init.is(t_typeName)) + throw SemanticHelper.typeMismatch(init.loc, t_init, t_typeName); + t_var = t_typeName; + } + env.venv.put(name, t_var); + } +} diff --git a/src/main/java/absyn/Exp.java b/src/main/java/absyn/Exp.java index ee335f8..f75f6b1 100644 --- a/src/main/java/absyn/Exp.java +++ b/src/main/java/absyn/Exp.java @@ -1,30 +1,30 @@ -package absyn; - -import env.Env; -import parse.Loc; -import types.Type; - -public abstract class Exp extends AST { - - // Type of the expression, calculated by the semantic analyser - public Type type; - - public Exp(Loc loc) { - super(loc); - } - - // Obtain the type of the expression as a string prefixed by the given text. - protected String annotateType(String text) { - final String theType = type == null ? "" : "\n<" + type + ">"; - return text + theType; - } - - // Do semantic analysis of the expression - public Type semantic(Env env) { - type = semantic_(env); - return type; - } - - // Type check the expression. Should be defined in the concrete subclasses. - protected abstract Type semantic_(Env env); -} +package absyn; + +import env.Env; +import parse.Loc; +import types.Type; + +public abstract class Exp extends AST { + + // Type of the expression, calculated by the semantic analyser + public Type type; + + public Exp(Loc loc) { + super(loc); + } + + // Obtain the type of the expression as a string prefixed by the given text. + protected String annotateType(String text) { + final String theType = type == null ? "" : "\n<" + type + ">"; + return text + theType; + } + + // Do semantic analysis of the expression + public Type semantic(Env env) { + type = semantic_(env); + return type; + } + + // Type check the expression. Should be defined in the concrete subclasses. + protected abstract Type semantic_(Env env); +} diff --git a/src/main/java/absyn/ExpAssign.java b/src/main/java/absyn/ExpAssign.java new file mode 100644 index 0000000..5d73dc4 --- /dev/null +++ b/src/main/java/absyn/ExpAssign.java @@ -0,0 +1,42 @@ +package absyn; + +import env.Env; +import error.ErrorHelper; +import javaslang.collection.Tree; +import parse.Loc; +import types.BOOL; +import types.INT; +import types.REAL; +import types.Type; + +import static error.ErrorHelper.fatal; +import static semantic.SemanticHelper.*; + +public class ExpAssign extends Exp { + + public final Var var; + public final Exp exp; + + public ExpAssign(Loc loc, Var var, Exp exp) { + super(loc); + this.var = var; + this.exp = exp; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpAssign"), var.toTree(), exp.toTree()); + } + + @Override + protected Type semantic_(Env env) { + final Type t_var = var.semantic(env); + final Type t_exp = exp.semantic(env); + + if (!t_var.is(t_exp)) { + throw typeMismatch(exp.loc, t_exp, t_var); + } + return t_var; + } + +} diff --git a/src/main/java/absyn/ExpBinOp.java b/src/main/java/absyn/ExpBinOp.java index dce0d7d..4747f80 100644 --- a/src/main/java/absyn/ExpBinOp.java +++ b/src/main/java/absyn/ExpBinOp.java @@ -1,74 +1,74 @@ -package absyn; - -import env.Env; -import error.ErrorHelper; -import javaslang.collection.Tree; -import parse.Loc; -import types.BOOL; -import types.INT; -import types.REAL; -import types.Type; - -import static error.ErrorHelper.fatal; -import static semantic.SemanticHelper.*; - -public class ExpBinOp extends Exp { - - public enum Op { - PLUS, MINUS, TIMES, DIV, - AND, OR - } - - public final Op op; - public final Exp left; - public final Exp right; - - public ExpBinOp(Loc loc, Op op, Exp left, Exp right) { - super(loc); - this.op = op; - this.left = left; - this.right = right; - } - - @Override - public Tree.Node toTree() { - return Tree.of(annotateType("ExpBinOp: " + op), left.toTree(), right.toTree()); - } - - @Override - protected Type semantic_(Env env) { - final Type t_left = left.semantic(env); - final Type t_right = right.semantic(env); - - switch (op) { - case PLUS: - case MINUS: - case TIMES: - case DIV: - if (!t_left.is(INT.T, REAL.T)) - throw typeMismatch(left.loc, t_left, INT.T, REAL.T); - - if (!t_right.is(INT.T, REAL.T)) - throw typeMismatch(right.loc, t_right, INT.T, REAL.T); - - if (t_left.is(REAL.T) || t_right.is(REAL.T)) - return REAL.T; - - return INT.T; - - case AND: - case OR: - if (!t_left.is(BOOL.T)) - throw typeMismatch(left.loc, t_left, BOOL.T); - - if (!t_right.is(BOOL.T)) - throw typeMismatch(right.loc, t_right, BOOL.T); - - return BOOL.T; - - default: - throw fatal("unexpected invalid operator: %s", op); - } - } - -} +package absyn; + +import env.Env; +import error.ErrorHelper; +import javaslang.collection.Tree; +import parse.Loc; +import types.BOOL; +import types.INT; +import types.REAL; +import types.Type; + +import static error.ErrorHelper.fatal; +import static semantic.SemanticHelper.*; + +public class ExpBinOp extends Exp { + + public enum Op { + PLUS, MINUS, TIMES, DIV, + AND, OR + } + + public final Op op; + public final Exp left; + public final Exp right; + + public ExpBinOp(Loc loc, Op op, Exp left, Exp right) { + super(loc); + this.op = op; + this.left = left; + this.right = right; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpBinOp: " + op), left.toTree(), right.toTree()); + } + + @Override + protected Type semantic_(Env env) { + final Type t_left = left.semantic(env); + final Type t_right = right.semantic(env); + + switch (op) { + case PLUS: + case MINUS: + case TIMES: + case DIV: + if (!t_left.is(INT.T, REAL.T)) + throw typeMismatch(left.loc, t_left, INT.T, REAL.T); + + if (!t_right.is(INT.T, REAL.T)) + throw typeMismatch(right.loc, t_right, INT.T, REAL.T); + + if (t_left.is(REAL.T) || t_right.is(REAL.T)) + return REAL.T; + + return INT.T; + + case AND: + case OR: + if (!t_left.is(BOOL.T)) + throw typeMismatch(left.loc, t_left, BOOL.T); + + if (!t_right.is(BOOL.T)) + throw typeMismatch(right.loc, t_right, BOOL.T); + + return BOOL.T; + + default: + throw fatal("unexpected invalid operator: %s", op); + } + } + +} diff --git a/src/main/java/absyn/ExpBool.java b/src/main/java/absyn/ExpBool.java index 68d77bd..8f2a0dd 100644 --- a/src/main/java/absyn/ExpBool.java +++ b/src/main/java/absyn/ExpBool.java @@ -1,27 +1,27 @@ -package absyn; - -import env.Env; -import javaslang.collection.Tree; -import parse.Loc; -import types.BOOL; -import types.Type; - -public class ExpBool extends Exp { - - public final String value; - - public ExpBool(Loc loc, String value) { - super(loc); - this.value = value; - } - - @Override - public Tree.Node toTree() { - return Tree.of(annotateType("ExpBool: " + value)); - } - - @Override - protected Type semantic_(Env env) { - return BOOL.T; - } -} +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import types.BOOL; +import types.Type; + +public class ExpBool extends Exp { + + public final String value; + + public ExpBool(Loc loc, String value) { + super(loc); + this.value = value; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpBool: " + value)); + } + + @Override + protected Type semantic_(Env env) { + return BOOL.T; + } +} diff --git a/src/main/java/absyn/ExpCall.java b/src/main/java/absyn/ExpCall.java index eaf1049..1044fea 100644 --- a/src/main/java/absyn/ExpCall.java +++ b/src/main/java/absyn/ExpCall.java @@ -1,73 +1,73 @@ -package absyn; - -import env.Env; -import javaslang.collection.List; -import javaslang.collection.Tree; -import parse.Loc; -import types.FUNCTION; -import types.Type; - -import static semantic.SemanticHelper.*; - - -public class ExpCall extends Exp { - - public final String function; - public final List args; - - public ExpCall(Loc loc, String function, List args) { - super(loc); - this.function = function; - this.args = args; - } - - @Override - public Tree.Node toTree() { - return Tree.of(annotateType("ExpCall"), - Tree.of(function.toString()), - Tree.of("args", - args.map(Exp::toTree))); - } - - @Override - protected Type semantic_(Env env) { - // analyse all arguments - List t_args = args.map(exp -> exp.semantic(env)); - // search the function name in the environment - Type entry = env.venv.get(function); - // check whether it was found and report error if not found - if (entry == null) - throw undefined(loc, "function", function); - // check whether it really names a function - if (!(entry instanceof FUNCTION)) - throw notAFunction(loc, function); - // it is a function, so get a more specific version of the entry - FUNCTION signature = (FUNCTION) entry; - // check the arguments: walk the list of parameters and the list of - // arguments in parallel, checking each argument - // it finishes when the end of any of the lists are reached - List parameters = signature.formals; - List arguments = args; - List t_arguments = t_args; - while (parameters.nonEmpty() && arguments.nonEmpty()) { - Exp arg = arguments.head(); - Type t_arg = t_arguments.head(); - Type t_par = parameters.head(); - // are the argument of the expected type? - if (!t_arg.is(t_par)) - throw typeMismatch(arg.loc, t_arg, t_par); - // advances to the next argument - parameters = parameters.tail(); - arguments = arguments.tail(); - t_arguments = t_arguments.tail(); - } - // at the end there may be more arguments... - if (arguments.nonEmpty()) - throw tooMuchArguments(loc, function); - // ... or more parameters - if (parameters.nonEmpty()) - throw tooFewArguments(loc, function); - return signature.result; - } - -} +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import parse.Loc; +import types.FUNCTION; +import types.Type; + +import static semantic.SemanticHelper.*; + + +public class ExpCall extends Exp { + + public final String function; + public final List args; + + public ExpCall(Loc loc, String function, List args) { + super(loc); + this.function = function; + this.args = args; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpCall"), + Tree.of(function.toString()), + Tree.of("args", + args.map(Exp::toTree))); + } + + @Override + protected Type semantic_(Env env) { + // analyse all arguments + List t_args = args.map(exp -> exp.semantic(env)); + // search the function name in the environment + Type entry = env.venv.get(function); + // check whether it was found and report error if not found + if (entry == null) + throw undefined(loc, "function", function); + // check whether it really names a function + if (!(entry instanceof FUNCTION)) + throw notAFunction(loc, function); + // it is a function, so get a more specific version of the entry + FUNCTION signature = (FUNCTION) entry; + // check the arguments: walk the list of parameters and the list of + // arguments in parallel, checking each argument + // it finishes when the end of any of the lists are reached + List parameters = signature.formals; + List arguments = args; + List t_arguments = t_args; + while (parameters.nonEmpty() && arguments.nonEmpty()) { + Exp arg = arguments.head(); + Type t_arg = t_arguments.head(); + Type t_par = parameters.head(); + // are the argument of the expected type? + if (!t_arg.is(t_par)) + throw typeMismatch(arg.loc, t_arg, t_par); + // advances to the next argument + parameters = parameters.tail(); + arguments = arguments.tail(); + t_arguments = t_arguments.tail(); + } + // at the end there may be more arguments... + if (arguments.nonEmpty()) + throw tooMuchArguments(loc, function); + // ... or more parameters + if (parameters.nonEmpty()) + throw tooFewArguments(loc, function); + return signature.result; + } + +} diff --git a/src/main/java/absyn/ExpInt.java b/src/main/java/absyn/ExpInt.java index 24d6b77..f11f85e 100644 --- a/src/main/java/absyn/ExpInt.java +++ b/src/main/java/absyn/ExpInt.java @@ -1,27 +1,27 @@ -package absyn; - -import env.Env; -import javaslang.collection.Tree; -import parse.Loc; -import types.INT; -import types.Type; - -public class ExpInt extends Exp { - - public final String value; - - public ExpInt(Loc loc, String value) { - super(loc); - this.value = value; - } - - @Override - public Tree.Node toTree() { - return Tree.of(annotateType("ExpInt: " + value)); - } - - @Override - protected Type semantic_(Env env) { - return INT.T; - } -} +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import types.INT; +import types.Type; + +public class ExpInt extends Exp { + + public final String value; + + public ExpInt(Loc loc, String value) { + super(loc); + this.value = value; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpInt: " + value)); + } + + @Override + protected Type semantic_(Env env) { + return INT.T; + } +} diff --git a/src/main/java/absyn/ExpLet.java b/src/main/java/absyn/ExpLet.java index d7f0a66..80a3eac 100644 --- a/src/main/java/absyn/ExpLet.java +++ b/src/main/java/absyn/ExpLet.java @@ -1,38 +1,38 @@ -package absyn; - -import env.Env; -import javaslang.collection.List; -import javaslang.collection.Tree; -import parse.Loc; -import types.Type; - -public class ExpLet extends Exp { - - public final List decs; - public final Exp body; - - public ExpLet(Loc loc, List decs, Exp body) { - super(loc); - this.decs = decs; - this.body = body; - } - - @Override - public Tree.Node toTree() { - return Tree.of(annotateType("ExpLet"), - Tree.of("Decs", - decs.map(Dec::toTree)), - body.toTree()); - } - - @Override - protected Type semantic_(Env env) { - env.tenv.beginScope();; - env.venv.beginScope(); - decs.forEach(d -> d.semantic(env)); - Type t_body = body.semantic(env); - env.tenv.endScope(); - env.venv.endScope(); - return t_body; - } -} +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import parse.Loc; +import types.Type; + +public class ExpLet extends Exp { + + public final List decs; + public final Exp body; + + public ExpLet(Loc loc, List decs, Exp body) { + super(loc); + this.decs = decs; + this.body = body; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpLet"), + Tree.of("Decs", + decs.map(Dec::toTree)), + body.toTree()); + } + + @Override + protected Type semantic_(Env env) { + env.tenv.beginScope();; + env.venv.beginScope(); + decs.forEach(d -> d.semantic(env)); + Type t_body = body.semantic(env); + env.tenv.endScope(); + env.venv.endScope(); + return t_body; + } +} diff --git a/src/main/java/absyn/ExpNegate.java b/src/main/java/absyn/ExpNegate.java index c6bd4dc..3225fe4 100644 --- a/src/main/java/absyn/ExpNegate.java +++ b/src/main/java/absyn/ExpNegate.java @@ -1,37 +1,37 @@ -package absyn; - -import env.Env; -import javaslang.collection.Tree; -import parse.Loc; -import types.INT; -import types.REAL; -import types.Type; - -import static error.ErrorHelper.*; -import static semantic.SemanticHelper.*; - -public class ExpNegate extends Exp { - - public final Exp arg; - - public ExpNegate(Loc loc, Exp arg) { - super(loc); - this.arg = arg; - } - - @Override - public Tree.Node toTree() { - return Tree.of(annotateType("ExpNegate"), arg.toTree()); - } - - @Override - protected Type semantic_(Env env) { - final Type t_arg = arg.semantic(env); - - if (t_arg instanceof INT || t_arg instanceof REAL) - return t_arg; - - throw typeMismatch(arg.loc, t_arg, INT.T, REAL.T); - } - -} +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import types.INT; +import types.REAL; +import types.Type; + +import static error.ErrorHelper.*; +import static semantic.SemanticHelper.*; + +public class ExpNegate extends Exp { + + public final Exp arg; + + public ExpNegate(Loc loc, Exp arg) { + super(loc); + this.arg = arg; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpNegate"), arg.toTree()); + } + + @Override + protected Type semantic_(Env env) { + final Type t_arg = arg.semantic(env); + + if (t_arg instanceof INT || t_arg instanceof REAL) + return t_arg; + + throw typeMismatch(arg.loc, t_arg, INT.T, REAL.T); + } + +} diff --git a/src/main/java/absyn/ExpReal.java b/src/main/java/absyn/ExpReal.java index 14e500f..9baa19c 100644 --- a/src/main/java/absyn/ExpReal.java +++ b/src/main/java/absyn/ExpReal.java @@ -1,27 +1,27 @@ -package absyn; - -import env.Env; -import javaslang.collection.Tree; -import parse.Loc; -import types.REAL; -import types.Type; - -public class ExpReal extends Exp { - - public final String value; - - public ExpReal(Loc loc, String value) { - super(loc); - this.value = value; - } - - @Override - public Tree.Node toTree() { - return Tree.of(annotateType("ExpReal: " + value)); - } - - @Override - protected Type semantic_(Env env) { - return REAL.T; - } -} +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import types.REAL; +import types.Type; + +public class ExpReal extends Exp { + + public final String value; + + public ExpReal(Loc loc, String value) { + super(loc); + this.value = value; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpReal: " + value)); + } + + @Override + protected Type semantic_(Env env) { + return REAL.T; + } +} diff --git a/src/main/java/absyn/ExpSeq.java b/src/main/java/absyn/ExpSeq.java index 0562914..3bb5907 100644 --- a/src/main/java/absyn/ExpSeq.java +++ b/src/main/java/absyn/ExpSeq.java @@ -1,33 +1,33 @@ -package absyn; - -import env.Env; -import javaslang.collection.List; -import javaslang.collection.Tree; -import parse.Loc; -import types.Type; -import types.UNIT; - -public class ExpSeq extends Exp { - - public final List exps; - - public ExpSeq(Loc loc, List exps) { - super(loc); - this.exps = exps; - } - - @Override - public Tree.Node toTree() { - return Tree.of(annotateType("ExpSeq"), - exps.map(Exp::toTree)); - } - - @Override - protected Type semantic_(Env env) { - Type t = UNIT.T; - for (Exp e : exps) - t = e.semantic_(env); - return t; - } - -} +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import parse.Loc; +import types.Type; +import types.UNIT; + +public class ExpSeq extends Exp { + + public final List exps; + + public ExpSeq(Loc loc, List exps) { + super(loc); + this.exps = exps; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpSeq"), + exps.map(Exp::toTree)); + } + + @Override + protected Type semantic_(Env env) { + Type t = UNIT.T; + for (Exp e : exps) + t = e.semantic_(env); + return t; + } + +} diff --git a/src/main/java/absyn/ExpVar.java b/src/main/java/absyn/ExpVar.java index b445549..68d903e 100644 --- a/src/main/java/absyn/ExpVar.java +++ b/src/main/java/absyn/ExpVar.java @@ -1,28 +1,28 @@ -package absyn; - -import env.Env; -import javaslang.collection.Tree; -import parse.Loc; -import types.INT; -import types.Type; - -public class ExpVar extends Exp { - - public final Var variable; - - public ExpVar(Loc loc, Var variable) { - super(loc); - this.variable = variable; - } - - @Override - public Tree.Node toTree() { - return Tree.of(annotateType("ExpVar"), - variable.toTree()); - } - - @Override - protected Type semantic_(Env env) { - return variable.semantic(env); - } -} +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import types.INT; +import types.Type; + +public class ExpVar extends Exp { + + public final Var variable; + + public ExpVar(Loc loc, Var variable) { + super(loc); + this.variable = variable; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpVar"), + variable.toTree()); + } + + @Override + protected Type semantic_(Env env) { + return variable.semantic(env); + } +} diff --git a/src/main/java/absyn/Var.java b/src/main/java/absyn/Var.java index 9dd9988..fefb876 100644 --- a/src/main/java/absyn/Var.java +++ b/src/main/java/absyn/Var.java @@ -1,30 +1,30 @@ -package absyn; - -import env.Env; -import parse.Loc; -import types.Type; - -public abstract class Var extends AST { - - // Type of the expression, calculated by the semantic analyser - public Type type; - - public Var(Loc loc) { - super(loc); - } - - // Obtain the type of the expression as a string prefixed by the given text. - protected String annotateType(String text) { - final String theType = type == null ? "" : "\n<" + type + ">"; - return text + theType; - } - - // Do semantic analysis of the expression - public Type semantic(Env env) { - type = semantic_(env); - return type; - } - - // Type check the expression. Should be defined in the concrete subclasses. - protected abstract Type semantic_(Env env); -} +package absyn; + +import env.Env; +import parse.Loc; +import types.Type; + +public abstract class Var extends AST { + + // Type of the expression, calculated by the semantic analyser + public Type type; + + public Var(Loc loc) { + super(loc); + } + + // Obtain the type of the expression as a string prefixed by the given text. + protected String annotateType(String text) { + final String theType = type == null ? "" : "\n<" + type + ">"; + return text + theType; + } + + // Do semantic analysis of the expression + public Type semantic(Env env) { + type = semantic_(env); + return type; + } + + // Type check the expression. Should be defined in the concrete subclasses. + protected abstract Type semantic_(Env env); +} diff --git a/src/main/java/absyn/VarSimple.java b/src/main/java/absyn/VarSimple.java index 3bd4efc..92c6f07 100644 --- a/src/main/java/absyn/VarSimple.java +++ b/src/main/java/absyn/VarSimple.java @@ -1,32 +1,32 @@ -package absyn; - -import env.Env; -import javaslang.collection.Tree; -import parse.Loc; -import semantic.SemanticHelper; -import types.INT; -import types.Type; - -public class VarSimple extends Var { - - public final String name; - - public VarSimple(Loc loc, String name) { - super(loc); - this.name = name; - } - - @Override - public Tree.Node toTree() { - return Tree.of(annotateType("VarSimple: " + name)); - } - - @Override - protected Type semantic_(Env env) { - Type t = env.venv.get(name); - if (t == null) - throw SemanticHelper.undefined(loc, "variable", name); - return t; - } - -} +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import semantic.SemanticHelper; +import types.INT; +import types.Type; + +public class VarSimple extends Var { + + public final String name; + + public VarSimple(Loc loc, String name) { + super(loc); + this.name = name; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("VarSimple: " + name)); + } + + @Override + protected Type semantic_(Env env) { + Type t = env.venv.get(name); + if (t == null) + throw SemanticHelper.undefined(loc, "variable", name); + return t; + } + +} diff --git a/src/main/java/env/Env.java b/src/main/java/env/Env.java index dcb3547..80230cd 100644 --- a/src/main/java/env/Env.java +++ b/src/main/java/env/Env.java @@ -1,41 +1,41 @@ -package env; - -import types.*; - -public class Env { - - public Table tenv; - public Table venv; - - public Env() { - tenv = new Table(); - put(tenv, "unit", UNIT.T); - put(tenv, "int", INT.T); - put(tenv, "real", REAL.T); - put(tenv, "bool", BOOL.T); - - venv = new Table(); - put(venv, "print_int", new FUNCTION(UNIT.T, INT.T)); - put(venv, "print_real", new FUNCTION(UNIT.T, REAL.T)); - put(venv, "print_unit", new FUNCTION(UNIT.T, UNIT.T)); - put(venv, "print_bool", new FUNCTION(UNIT.T, BOOL.T)); - put(venv, "round", new FUNCTION(INT.T, REAL.T)); - put(venv, "ceil", new FUNCTION(INT.T, REAL.T)); - put(venv, "floor", new FUNCTION(INT.T, REAL.T)); - put(venv, "real", new FUNCTION(REAL.T, INT.T)); - put(venv, "not", new FUNCTION(BOOL.T, BOOL.T)); - } - - @Override - public String toString() { - return "Env{" + - "tenv=" + tenv + - ", venv=" + venv + - '}'; - } - - private static void put(Table table, String name, E value) { - table.put(name.intern(), value); - } - -} +package env; + +import types.*; + +public class Env { + + public Table tenv; + public Table venv; + + public Env() { + tenv = new Table(); + put(tenv, "unit", UNIT.T); + put(tenv, "int", INT.T); + put(tenv, "real", REAL.T); + put(tenv, "bool", BOOL.T); + + venv = new Table(); + put(venv, "print_int", new FUNCTION(UNIT.T, INT.T)); + put(venv, "print_real", new FUNCTION(UNIT.T, REAL.T)); + put(venv, "print_unit", new FUNCTION(UNIT.T, UNIT.T)); + put(venv, "print_bool", new FUNCTION(UNIT.T, BOOL.T)); + put(venv, "round", new FUNCTION(INT.T, REAL.T)); + put(venv, "ceil", new FUNCTION(INT.T, REAL.T)); + put(venv, "floor", new FUNCTION(INT.T, REAL.T)); + put(venv, "real", new FUNCTION(REAL.T, INT.T)); + put(venv, "not", new FUNCTION(BOOL.T, BOOL.T)); + } + + @Override + public String toString() { + return "Env{" + + "tenv=" + tenv + + ", venv=" + venv + + '}'; + } + + private static void put(Table table, String name, E value) { + table.put(name.intern(), value); + } + +} diff --git a/src/main/java/env/Table.java b/src/main/java/env/Table.java index ec2e0b0..16b1fc8 100644 --- a/src/main/java/env/Table.java +++ b/src/main/java/env/Table.java @@ -1,83 +1,83 @@ -package env; - -import java.util.IdentityHashMap; -import java.util.Map; -import java.util.Set; - -class Binder { - V value; - String prevtop; - Binder tail; - - Binder(V v, String p, Binder t) { - value = v; - prevtop = p; - tail = t; - } -} - -/** - * The Table class is similar to java.util.Dictionary, except that each key must - * be a symbol and there is a scope mechanism. - */ - -public class Table { - private Map> dict; - private String top; - private Binder marks; - - public Table() { - dict = new IdentityHashMap>(); - } - - /** - * Gets the object associated with the specified symbol in the Table. - */ - public V get(String key) { - Binder e = dict.get(key); - if (e == null) - return null; - else - return e.value; - } - - /** - * Puts the specified value into the Table, bound to the specified symbol. - */ - public void put(String key, V value) { - dict.put(key, new Binder(value, top, dict.get(key))); - top = key; - } - - /** - * Remembers the current state of the Table. - */ - public void beginScope() { - marks = new Binder(null, top, marks); - top = null; - } - - /** - * Restores the table to what it was at the most recent beginScope that has - * not already been ended. - */ - public void endScope() { - while (top != null) { - Binder e = dict.get(top); - if (e.tail != null) - dict.put(top, e.tail); - else - dict.remove(top); - top = e.prevtop; - } - top = marks.prevtop; - marks = marks.tail; - } - - /** - * Returns a Set view of the Table's symbols. - */ - public Set keySet() { - return dict.keySet(); - } -} +package env; + +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; + +class Binder { + V value; + String prevtop; + Binder tail; + + Binder(V v, String p, Binder t) { + value = v; + prevtop = p; + tail = t; + } +} + +/** + * The Table class is similar to java.util.Dictionary, except that each key must + * be a symbol and there is a scope mechanism. + */ + +public class Table { + private Map> dict; + private String top; + private Binder marks; + + public Table() { + dict = new IdentityHashMap>(); + } + + /** + * Gets the object associated with the specified symbol in the Table. + */ + public V get(String key) { + Binder e = dict.get(key); + if (e == null) + return null; + else + return e.value; + } + + /** + * Puts the specified value into the Table, bound to the specified symbol. + */ + public void put(String key, V value) { + dict.put(key, new Binder(value, top, dict.get(key))); + top = key; + } + + /** + * Remembers the current state of the Table. + */ + public void beginScope() { + marks = new Binder(null, top, marks); + top = null; + } + + /** + * Restores the table to what it was at the most recent beginScope that has + * not already been ended. + */ + public void endScope() { + while (top != null) { + Binder e = dict.get(top); + if (e.tail != null) + dict.put(top, e.tail); + else + dict.remove(top); + top = e.prevtop; + } + top = marks.prevtop; + marks = marks.tail; + } + + /** + * Returns a Set view of the Table's symbols. + */ + public Set keySet() { + return dict.keySet(); + } +} diff --git a/src/main/java/error/CompilerError.java b/src/main/java/error/CompilerError.java index 3b20a1a..ca765c6 100644 --- a/src/main/java/error/CompilerError.java +++ b/src/main/java/error/CompilerError.java @@ -1,18 +1,18 @@ -package error; - -import parse.Loc; - -public class CompilerError extends RuntimeException { - - public CompilerError(String message) { - super(message); - } - - public CompilerError(String format, Object... args) { - this(String.format(format, args)); - } - - public CompilerError(Loc loc, String format, Object... args) { - this(loc + " " + String.format(format, args)); - } -} +package error; + +import parse.Loc; + +public class CompilerError extends RuntimeException { + + public CompilerError(String message) { + super(message); + } + + public CompilerError(String format, Object... args) { + this(String.format(format, args)); + } + + public CompilerError(Loc loc, String format, Object... args) { + this(loc + " " + String.format(format, args)); + } +} diff --git a/src/main/java/error/ErrorHelper.java b/src/main/java/error/ErrorHelper.java index 6bd33c2..c315276 100644 --- a/src/main/java/error/ErrorHelper.java +++ b/src/main/java/error/ErrorHelper.java @@ -1,23 +1,23 @@ -package error; - -import parse.Loc; - -public interface ErrorHelper { - - static CompilerError error(String message) { - return new CompilerError(message); - } - - static CompilerError error(String format, Object... args) { - return error(String.format(format, args)); - } - - static CompilerError error(Loc loc, String format, Object... args) { - return error(loc + " " + String.format(format, args)); - } - - static FatalError fatal(String format, Object... args) { - return new FatalError(format, args); - } - -} +package error; + +import parse.Loc; + +public interface ErrorHelper { + + static CompilerError error(String message) { + return new CompilerError(message); + } + + static CompilerError error(String format, Object... args) { + return error(String.format(format, args)); + } + + static CompilerError error(Loc loc, String format, Object... args) { + return error(loc + " " + String.format(format, args)); + } + + static FatalError fatal(String format, Object... args) { + return new FatalError(format, args); + } + +} diff --git a/src/main/java/error/FatalError.java b/src/main/java/error/FatalError.java index 84485d4..3c3033f 100644 --- a/src/main/java/error/FatalError.java +++ b/src/main/java/error/FatalError.java @@ -1,13 +1,13 @@ -package error; - -public class FatalError extends RuntimeException { - - public FatalError(String message) { - super("fatal: " + message); - } - - public FatalError(String format, Object... args) { - this(String.format(format, args)); - } - -} +package error; + +public class FatalError extends RuntimeException { + + public FatalError(String message) { + super("fatal: " + message); + } + + public FatalError(String format, Object... args) { + this(String.format(format, args)); + } + +} diff --git a/src/main/java/main/Driver.java b/src/main/java/main/Driver.java index 57edd8b..eadfae4 100644 --- a/src/main/java/main/Driver.java +++ b/src/main/java/main/Driver.java @@ -1,189 +1,189 @@ -package main; - -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; - -import absyn.AST; -import absyn.Exp; -import com.beust.jcommander.JCommander; -import com.beust.jcommander.Parameter; -import com.beust.jcommander.ParameterException; -import error.CompilerError; -import java_cup.runtime.Symbol; -import javaslang.render.dot.DotFile; -import javaslang.render.text.Boxes; -import javaslang.render.text.PrettyPrinter; -import parse.SymbolConstants; -import parse.Lexer; -import parse.Parser; - -import static error.ErrorHelper.fatal; - -// command line options -class DriverOptions { - @Parameter(description = "") - public List parameters = new ArrayList<>(); - - @Parameter(names = {"--help", "-h"}, description = "Usage help", help = true) - public boolean help = false; - - @Parameter(names = {"--lexer"}, description = "Lexical analysis") - public boolean lexer = false; - - @Parameter(names = {"--parser"}, description = "Syntax analysis") - public boolean parser = true; - - @Parameter(names = {"--pp-ast"}, description = "Pretty print syntax tree") - public boolean pp_ast = false; - - @Parameter(names = {"--pp-anotated-ast"}, description = "Pretty print annotated syntax tree") - public boolean pp_annotated_ast = false; - - @Parameter(names = {"--box-ast"}, description = "Boxed syntax tree") - public boolean box_ast = false; - - @Parameter(names = {"--box-annotated-ast"}, description = "Boxed annotated syntax tree") - public boolean box_annotated_ast = true; - - @Parameter(names = {"--dot-ast"}, description = "Generate dot file of syntax tree") - public boolean dot_ast = false; - - @Parameter(names = {"--dot-annotated-ast"}, description = "Generate dot file of annotated syntax tree") - public boolean dot_annotted_ast = true; -} - -// main -public class Driver { - - public static void main(String[] args) { - // parse command line options - final DriverOptions options = new DriverOptions(); - final JCommander jCommander = new JCommander(options); - jCommander.setProgramName("Driver"); - - try { - jCommander.parse(args); - } - catch (ParameterException e) { - System.out.println(e.getMessage()); - jCommander.usage(); - System.exit(1); - } - - if (options.help) { - jCommander.usage(); - return; - } - - Reader input = null; - String name = null; - try { - // set the input (source code) to compile - if (options.parameters.isEmpty()) { - name = "unknown"; - input = new InputStreamReader(System.in); - } - else { - name = options.parameters.get(0); - input = new FileReader(name); - } - - // do only lexical analyses - if (options.lexer) - lexicalAnalysis(name, input); - - // do only lexical analyses - if (options.parser) - syntaxAnalysis(options, name, input); - } - catch (CompilerError e) { - System.out.println(e.getMessage()); - System.exit(3); - } - catch (IOException e) { - System.out.println(e.getMessage()); - System.exit(2); - } - catch (Exception e) { - System.out.println(e.getMessage()); - e.printStackTrace(); - System.exit(3); - } - finally { - // closes the input file - if (input instanceof FileReader) - try { - input.close(); - } - catch (IOException e) { - System.out.println(e.getMessage()); - System.exit(4); - } - } - } - - public static void lexicalAnalysis(String name, Reader input) throws IOException { - final Lexer lexer = new Lexer(input, "unknown"); - Symbol tok; - do { - tok = lexer.next_token(); - System.out.printf("%-55s %-8s %s%n", - tok, - SymbolConstants.terminalNames[tok.sym], - tok.value == null ? "" : tok.value); - } while (tok.sym != SymbolConstants.EOF); - } - - public static void syntaxAnalysis(DriverOptions options, String name, Reader input) throws Exception { - final Lexer lexer = new Lexer(input, "unknown"); - final Parser parser = new Parser(lexer); - final Symbol result = parser.parse(); - //System.out.println(result); - - if (!(result.value instanceof AST)) - throw fatal("internal error: program should be an AST"); - - final AST parseTree = (AST) result.value; - if (options.pp_ast) { - System.out.println("===Abstract syntax tree:==========="); - System.out.println(); - System.out.println(PrettyPrinter.pp(parseTree.toTree())); - System.out.println(); - } - if (options.box_ast) { - System.out.println("===Abstract syntax tree:==========="); - System.out.println(); - System.out.println(Boxes.box(parseTree.toTree())); - System.out.println(); - } - if (options.dot_ast) { - DotFile.write(parseTree.toTree(), name + ".dot"); - } - - if (!(parseTree instanceof Exp)) - throw fatal("internal error: program should be an expression"); - - final Exp main = (Exp) parseTree; - main.semantic(new env.Env()); - if (options.pp_annotated_ast) { - System.out.println("===Annotated abstract syntax tree:==========="); - System.out.println(); - System.out.println(PrettyPrinter.pp(parseTree.toTree())); - System.out.println(); - } - if (options.box_annotated_ast) { - System.out.println("===Annotated abstract syntax tree:==========="); - System.out.println(); - System.out.println(Boxes.box(parseTree.toTree())); - System.out.println(); - } - if (options.dot_annotted_ast) { - DotFile.write(parseTree.toTree(), name + ".annotated.dot"); - } - } - -} +package main; + +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + +import absyn.AST; +import absyn.Exp; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.ParameterException; +import error.CompilerError; +import java_cup.runtime.Symbol; +import javaslang.render.dot.DotFile; +import javaslang.render.text.Boxes; +import javaslang.render.text.PrettyPrinter; +import parse.SymbolConstants; +import parse.Lexer; +import parse.Parser; + +import static error.ErrorHelper.fatal; + +// command line options +class DriverOptions { + @Parameter(description = "") + public List parameters = new ArrayList<>(); + + @Parameter(names = {"--help", "-h"}, description = "Usage help", help = true) + public boolean help = false; + + @Parameter(names = {"--lexer"}, description = "Lexical analysis") + public boolean lexer = false; + + @Parameter(names = {"--parser"}, description = "Syntax analysis") + public boolean parser = true; + + @Parameter(names = {"--pp-ast"}, description = "Pretty print syntax tree") + public boolean pp_ast = false; + + @Parameter(names = {"--pp-anotated-ast"}, description = "Pretty print annotated syntax tree") + public boolean pp_annotated_ast = false; + + @Parameter(names = {"--box-ast"}, description = "Boxed syntax tree") + public boolean box_ast = false; + + @Parameter(names = {"--box-annotated-ast"}, description = "Boxed annotated syntax tree") + public boolean box_annotated_ast = true; + + @Parameter(names = {"--dot-ast"}, description = "Generate dot file of syntax tree") + public boolean dot_ast = false; + + @Parameter(names = {"--dot-annotated-ast"}, description = "Generate dot file of annotated syntax tree") + public boolean dot_annotted_ast = true; +} + +// main +public class Driver { + + public static void main(String[] args) { + // parse command line options + final DriverOptions options = new DriverOptions(); + final JCommander jCommander = new JCommander(options); + jCommander.setProgramName("Driver"); + + try { + jCommander.parse(args); + } + catch (ParameterException e) { + System.out.println(e.getMessage()); + jCommander.usage(); + System.exit(1); + } + + if (options.help) { + jCommander.usage(); + return; + } + + Reader input = null; + String name = null; + try { + // set the input (source code) to compile + if (options.parameters.isEmpty()) { + name = "unknown"; + input = new InputStreamReader(System.in); + } + else { + name = options.parameters.get(0); + input = new FileReader(name); + } + + // do only lexical analyses + if (options.lexer) + lexicalAnalysis(name, input); + + // do only lexical analyses + if (options.parser) + syntaxAnalysis(options, name, input); + } + catch (CompilerError e) { + System.out.println(e.getMessage()); + System.exit(3); + } + catch (IOException e) { + System.out.println(e.getMessage()); + System.exit(2); + } + catch (Exception e) { + System.out.println(e.getMessage()); + e.printStackTrace(); + System.exit(3); + } + finally { + // closes the input file + if (input instanceof FileReader) + try { + input.close(); + } + catch (IOException e) { + System.out.println(e.getMessage()); + System.exit(4); + } + } + } + + public static void lexicalAnalysis(String name, Reader input) throws IOException { + final Lexer lexer = new Lexer(input, "unknown"); + Symbol tok; + do { + tok = lexer.next_token(); + System.out.printf("%-55s %-8s %s%n", + tok, + SymbolConstants.terminalNames[tok.sym], + tok.value == null ? "" : tok.value); + } while (tok.sym != SymbolConstants.EOF); + } + + public static void syntaxAnalysis(DriverOptions options, String name, Reader input) throws Exception { + final Lexer lexer = new Lexer(input, "unknown"); + final Parser parser = new Parser(lexer); + final Symbol result = parser.parse(); + //System.out.println(result); + + if (!(result.value instanceof AST)) + throw fatal("internal error: program should be an AST"); + + final AST parseTree = (AST) result.value; + if (options.pp_ast) { + System.out.println("===Abstract syntax tree:==========="); + System.out.println(); + System.out.println(PrettyPrinter.pp(parseTree.toTree())); + System.out.println(); + } + if (options.box_ast) { + System.out.println("===Abstract syntax tree:==========="); + System.out.println(); + System.out.println(Boxes.box(parseTree.toTree())); + System.out.println(); + } + if (options.dot_ast) { + DotFile.write(parseTree.toTree(), name + ".dot"); + } + + if (!(parseTree instanceof Exp)) + throw fatal("internal error: program should be an expression"); + + final Exp main = (Exp) parseTree; + main.semantic(new env.Env()); + if (options.pp_annotated_ast) { + System.out.println("===Annotated abstract syntax tree:==========="); + System.out.println(); + System.out.println(PrettyPrinter.pp(parseTree.toTree())); + System.out.println(); + } + if (options.box_annotated_ast) { + System.out.println("===Annotated abstract syntax tree:==========="); + System.out.println(); + System.out.println(Boxes.box(parseTree.toTree())); + System.out.println(); + } + if (options.dot_annotted_ast) { + DotFile.write(parseTree.toTree(), name + ".annotated.dot"); + } + } + +} diff --git a/src/main/java/main/SemantGui.java b/src/main/java/main/SemantGui.java index 0962e84..f3d7529 100644 --- a/src/main/java/main/SemantGui.java +++ b/src/main/java/main/SemantGui.java @@ -1,278 +1,278 @@ -package main; - -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Container; -import java.awt.Font; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.StringReader; -import javax.swing.*; -import javax.swing.tree.DefaultTreeModel; - -import error.CompilerError; -import java_cup.runtime.Symbol; -import javaslang.render.dot.DotFile; -import parse.Lexer; -import parse.Parser; -import absyn.Exp; - -@SuppressWarnings("serial") -public class SemantGui extends JFrame implements ActionListener { - private GridBagLayout layout = new GridBagLayout(); - private GridBagConstraints constraints = new GridBagConstraints(); - - private JButton openButton; - private JTextField fileField; - private JFileChooser chooser; - private JTextArea programArea; - private JTextArea logArea; - private JButton saveButton; - private JButton compileButton; - private JButton asyButton; - private JButton quitButton; - private JTree tree; - private JDialog dialog; - private JButton dialogClose; - - private Exp exp; - - public SemantGui() { - super("Panda Compiler"); - setLayout(new BorderLayout()); - - JToolBar toolBar = new JToolBar(); - toolBar.setFloatable(false); - toolBar.setRollover(true); - add(toolBar, BorderLayout.PAGE_START); - - JPanel panel_ = new JPanel(); - panel_.setLayout(new BoxLayout(panel_, BoxLayout.PAGE_AXIS)); - add(panel_, BorderLayout.CENTER); - - JLabel label = new JLabel("Source File:"); - label.setDisplayedMnemonic('F'); - toolBar.add(label); - - fileField = new JTextField(25); - label.setLabelFor(fileField); - fileField.addActionListener(this); - toolBar.add(fileField); - - openButton = new JButton("Browse"); - openButton.setMnemonic('B'); - openButton.addActionListener(this); - toolBar.add(openButton); - - toolBar.addSeparator(); - - saveButton = new JButton("Save"); - saveButton.setMnemonic('S'); - saveButton.addActionListener(this); - toolBar.add(saveButton); - - compileButton = new JButton("Compile"); - compileButton.setMnemonic('C'); - compileButton.addActionListener(this); - toolBar.add(compileButton); - - asyButton = new JButton("Show Tree"); - asyButton.setMnemonic('T'); - asyButton.addActionListener(this); - toolBar.add(asyButton); - - toolBar.addSeparator(); - - quitButton = new JButton("Quit"); - quitButton.setMnemonic('Q'); - quitButton.addActionListener(this); - toolBar.add(quitButton); - - chooser = new JFileChooser(); - - label = new JLabel("Program Source Code"); - label.setDisplayedMnemonic('P'); - panel_.add(label); - programArea = new JTextArea(12, 80); - programArea.setFont(new Font("Courier", Font.BOLD, 22)); - JScrollPane scrollPane = new JScrollPane(programArea); - label.setLabelFor(scrollPane); - panel_.add(scrollPane); - - label = new JLabel("Compiler Messages"); - label.setDisplayedMnemonicIndex(9); - panel_.add(label); - logArea = new JTextArea(5, 80); - scrollPane = new JScrollPane(logArea); - label.setLabelFor(scrollPane); - logArea.setFont(new Font("Courier", Font.BOLD, 22)); - panel_.add(scrollPane); - - JPanel panel = new JPanel(new GridLayout(1, 4)); - panel_.add(panel); - - label = new JLabel("Abstract Syntax Tree"); - label.setDisplayedMnemonicIndex(0); - panel_.add(label); - tree = new JTree(new DefaultTreeModel(null)); - tree.setFont(new Font("Courier", Font.BOLD, 22)); - scrollPane = new JScrollPane(tree); - label.setLabelFor(scrollPane); - panel_.add(scrollPane); - - pack(); - } - - private void addComponent(Container container, Component component, int row, int column, int width, int height, - int fill) { - constraints.gridx = column; - constraints.gridy = row; - constraints.gridwidth = width; - constraints.gridheight = height; - constraints.fill = fill; - constraints.weightx = 1; - constraints.weighty = 1; - constraints.insets = new Insets(2, 2, 2, 2); - layout.setConstraints(component, constraints); - container.add(component); - } - - public static void main(String args[]) throws Exception { - SemantGui application = new SemantGui(); - application.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - application.setVisible(true); - } - - private void readSource() { - try { - FileReader file = new FileReader(fileField.getText()); - StringBuilder str = new StringBuilder(); - while (true) { - int ch = file.read(); - if (ch == -1) - break; - str.append((char) ch); - } - file.close(); - programArea.setText(str.toString()); - } - catch (FileNotFoundException e1) { - JOptionPane.showMessageDialog(SemantGui.this, "File not found:\n" + fileField.getText(), - "CompError reading file", JOptionPane.ERROR_MESSAGE); - } - catch (IOException e2) { - JOptionPane.showMessageDialog(SemantGui.this, "CompError reading file:\n" + fileField.getText(), - "CompError reading file", JOptionPane.ERROR_MESSAGE); - } - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == openButton) { - int returnVal = chooser.showOpenDialog(SemantGui.this); - if (returnVal == JFileChooser.APPROVE_OPTION) - fileField.setText(chooser.getSelectedFile().getPath()); - readSource(); - } - if (e.getSource() == saveButton) { - String filePath = fileField.getText().trim(); - if (!filePath.isEmpty()) - chooser.setSelectedFile(new File(filePath)); - int returnVal = chooser.showSaveDialog(SemantGui.this); - if (returnVal == JFileChooser.APPROVE_OPTION) { - filePath = chooser.getSelectedFile().getPath(); - try { - FileWriter file = new FileWriter(filePath); - file.write(programArea.getText()); - file.close(); - fileField.setText(filePath); - } - catch (IOException e1) { - JOptionPane.showMessageDialog(SemantGui.this, - "CompError writing file:\n" + filePath, - "CompError writing file", - JOptionPane.ERROR_MESSAGE); - } - } - } - else if (e.getSource() == fileField) - readSource(); - else if (e.getSource() == compileButton) - compileProgram(); - else if (e.getSource() == asyButton) - asyGraph(); - else if (e.getSource() == dialogClose) - dialog.dispose(); - else if (e.getSource() == quitButton) - dispose(); - } - - private void compileProgram() { - StringReader file = new StringReader(programArea.getText()); - Lexer scanner = new Lexer(file, fileField.getText()); - Parser parser = new Parser(scanner, scanner.getSymbolFactory()); - try { - logArea.setText(""); - Symbol prog = parser.parse(); - exp = (Exp) prog.value; - DefaultTreeModel treeModel = new DefaultTreeModel(javaslang.render.swing.Tree.create(exp.toTree())); - tree.setModel(treeModel); - for (int row = 0; row < tree.getRowCount(); row++) - tree.expandRow(row); - types.Type et = exp.semantic(new env.Env()); - logArea.append("===> " + et.toString() + "\n"); - } - catch (CompilerError e) { - logArea.append(e.getMessage()); - } - catch (Exception e) { - JOptionPane.showMessageDialog(SemantGui.this, - "Error compiling program\n", - "Internal error compiling program\n" + - e.getStackTrace(), - JOptionPane.ERROR_MESSAGE); - } - - } - - private void asyGraph() { - if (exp != null) - try { - String imageType = "png"; - File tempfile = File.createTempFile("parsetree-", ".asy"); - tempfile.deleteOnExit(); - DotFile.write(exp.toTree(), tempfile); - File tempfile2 = File.createTempFile("parsetree-", "." + imageType); - tempfile2.deleteOnExit(); - String cmd[] = {"dot", "-Tpng", "-o", tempfile2.getPath(), tempfile.getPath()}; - Process proc = Runtime.getRuntime().exec(cmd, null, tempfile.getParentFile()); - proc.waitFor(); - dialog = new JDialog(SemantGui.this, "parse Tree"); - dialog.setLayout(layout); - Icon icon = new ImageIcon(tempfile2.getPath()); - JLabel label = new JLabel(icon); - JScrollPane scrollPane = new JScrollPane(label); - addComponent(dialog, scrollPane, 0, 0, 1, 1, GridBagConstraints.BOTH); - dialogClose = new JButton("Close"); - dialogClose.addActionListener(this); - addComponent(dialog, dialogClose, 1, 0, 1, 1, GridBagConstraints.NONE); - dialog.pack(); - dialog.setVisible(true); - } - catch (Exception e) { - JOptionPane.showMessageDialog(SemantGui.this, - "Error creating asy graph\n", - "Cannot create asy graph\n" + - e.getStackTrace(), - JOptionPane.ERROR_MESSAGE); - } - } -} +package main; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.StringReader; +import javax.swing.*; +import javax.swing.tree.DefaultTreeModel; + +import error.CompilerError; +import java_cup.runtime.Symbol; +import javaslang.render.dot.DotFile; +import parse.Lexer; +import parse.Parser; +import absyn.Exp; + +@SuppressWarnings("serial") +public class SemantGui extends JFrame implements ActionListener { + private GridBagLayout layout = new GridBagLayout(); + private GridBagConstraints constraints = new GridBagConstraints(); + + private JButton openButton; + private JTextField fileField; + private JFileChooser chooser; + private JTextArea programArea; + private JTextArea logArea; + private JButton saveButton; + private JButton compileButton; + private JButton asyButton; + private JButton quitButton; + private JTree tree; + private JDialog dialog; + private JButton dialogClose; + + private Exp exp; + + public SemantGui() { + super("Panda Compiler"); + setLayout(new BorderLayout()); + + JToolBar toolBar = new JToolBar(); + toolBar.setFloatable(false); + toolBar.setRollover(true); + add(toolBar, BorderLayout.PAGE_START); + + JPanel panel_ = new JPanel(); + panel_.setLayout(new BoxLayout(panel_, BoxLayout.PAGE_AXIS)); + add(panel_, BorderLayout.CENTER); + + JLabel label = new JLabel("Source File:"); + label.setDisplayedMnemonic('F'); + toolBar.add(label); + + fileField = new JTextField(25); + label.setLabelFor(fileField); + fileField.addActionListener(this); + toolBar.add(fileField); + + openButton = new JButton("Browse"); + openButton.setMnemonic('B'); + openButton.addActionListener(this); + toolBar.add(openButton); + + toolBar.addSeparator(); + + saveButton = new JButton("Save"); + saveButton.setMnemonic('S'); + saveButton.addActionListener(this); + toolBar.add(saveButton); + + compileButton = new JButton("Compile"); + compileButton.setMnemonic('C'); + compileButton.addActionListener(this); + toolBar.add(compileButton); + + asyButton = new JButton("Show Tree"); + asyButton.setMnemonic('T'); + asyButton.addActionListener(this); + toolBar.add(asyButton); + + toolBar.addSeparator(); + + quitButton = new JButton("Quit"); + quitButton.setMnemonic('Q'); + quitButton.addActionListener(this); + toolBar.add(quitButton); + + chooser = new JFileChooser(); + + label = new JLabel("Program Source Code"); + label.setDisplayedMnemonic('P'); + panel_.add(label); + programArea = new JTextArea(12, 80); + programArea.setFont(new Font("Courier", Font.BOLD, 22)); + JScrollPane scrollPane = new JScrollPane(programArea); + label.setLabelFor(scrollPane); + panel_.add(scrollPane); + + label = new JLabel("Compiler Messages"); + label.setDisplayedMnemonicIndex(9); + panel_.add(label); + logArea = new JTextArea(5, 80); + scrollPane = new JScrollPane(logArea); + label.setLabelFor(scrollPane); + logArea.setFont(new Font("Courier", Font.BOLD, 22)); + panel_.add(scrollPane); + + JPanel panel = new JPanel(new GridLayout(1, 4)); + panel_.add(panel); + + label = new JLabel("Abstract Syntax Tree"); + label.setDisplayedMnemonicIndex(0); + panel_.add(label); + tree = new JTree(new DefaultTreeModel(null)); + tree.setFont(new Font("Courier", Font.BOLD, 22)); + scrollPane = new JScrollPane(tree); + label.setLabelFor(scrollPane); + panel_.add(scrollPane); + + pack(); + } + + private void addComponent(Container container, Component component, int row, int column, int width, int height, + int fill) { + constraints.gridx = column; + constraints.gridy = row; + constraints.gridwidth = width; + constraints.gridheight = height; + constraints.fill = fill; + constraints.weightx = 1; + constraints.weighty = 1; + constraints.insets = new Insets(2, 2, 2, 2); + layout.setConstraints(component, constraints); + container.add(component); + } + + public static void main(String args[]) throws Exception { + SemantGui application = new SemantGui(); + application.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + application.setVisible(true); + } + + private void readSource() { + try { + FileReader file = new FileReader(fileField.getText()); + StringBuilder str = new StringBuilder(); + while (true) { + int ch = file.read(); + if (ch == -1) + break; + str.append((char) ch); + } + file.close(); + programArea.setText(str.toString()); + } + catch (FileNotFoundException e1) { + JOptionPane.showMessageDialog(SemantGui.this, "File not found:\n" + fileField.getText(), + "CompError reading file", JOptionPane.ERROR_MESSAGE); + } + catch (IOException e2) { + JOptionPane.showMessageDialog(SemantGui.this, "CompError reading file:\n" + fileField.getText(), + "CompError reading file", JOptionPane.ERROR_MESSAGE); + } + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == openButton) { + int returnVal = chooser.showOpenDialog(SemantGui.this); + if (returnVal == JFileChooser.APPROVE_OPTION) + fileField.setText(chooser.getSelectedFile().getPath()); + readSource(); + } + if (e.getSource() == saveButton) { + String filePath = fileField.getText().trim(); + if (!filePath.isEmpty()) + chooser.setSelectedFile(new File(filePath)); + int returnVal = chooser.showSaveDialog(SemantGui.this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + filePath = chooser.getSelectedFile().getPath(); + try { + FileWriter file = new FileWriter(filePath); + file.write(programArea.getText()); + file.close(); + fileField.setText(filePath); + } + catch (IOException e1) { + JOptionPane.showMessageDialog(SemantGui.this, + "CompError writing file:\n" + filePath, + "CompError writing file", + JOptionPane.ERROR_MESSAGE); + } + } + } + else if (e.getSource() == fileField) + readSource(); + else if (e.getSource() == compileButton) + compileProgram(); + else if (e.getSource() == asyButton) + asyGraph(); + else if (e.getSource() == dialogClose) + dialog.dispose(); + else if (e.getSource() == quitButton) + dispose(); + } + + private void compileProgram() { + StringReader file = new StringReader(programArea.getText()); + Lexer scanner = new Lexer(file, fileField.getText()); + Parser parser = new Parser(scanner, scanner.getSymbolFactory()); + try { + logArea.setText(""); + Symbol prog = parser.parse(); + exp = (Exp) prog.value; + DefaultTreeModel treeModel = new DefaultTreeModel(javaslang.render.swing.Tree.create(exp.toTree())); + tree.setModel(treeModel); + for (int row = 0; row < tree.getRowCount(); row++) + tree.expandRow(row); + types.Type et = exp.semantic(new env.Env()); + logArea.append("===> " + et.toString() + "\n"); + } + catch (CompilerError e) { + logArea.append(e.getMessage()); + } + catch (Exception e) { + JOptionPane.showMessageDialog(SemantGui.this, + "Error compiling program\n", + "Internal error compiling program\n" + + e.getStackTrace(), + JOptionPane.ERROR_MESSAGE); + } + + } + + private void asyGraph() { + if (exp != null) + try { + String imageType = "png"; + File tempfile = File.createTempFile("parsetree-", ".asy"); + tempfile.deleteOnExit(); + DotFile.write(exp.toTree(), tempfile); + File tempfile2 = File.createTempFile("parsetree-", "." + imageType); + tempfile2.deleteOnExit(); + String cmd[] = {"dot", "-Tpng", "-o", tempfile2.getPath(), tempfile.getPath()}; + Process proc = Runtime.getRuntime().exec(cmd, null, tempfile.getParentFile()); + proc.waitFor(); + dialog = new JDialog(SemantGui.this, "parse Tree"); + dialog.setLayout(layout); + Icon icon = new ImageIcon(tempfile2.getPath()); + JLabel label = new JLabel(icon); + JScrollPane scrollPane = new JScrollPane(label); + addComponent(dialog, scrollPane, 0, 0, 1, 1, GridBagConstraints.BOTH); + dialogClose = new JButton("Close"); + dialogClose.addActionListener(this); + addComponent(dialog, dialogClose, 1, 0, 1, 1, GridBagConstraints.NONE); + dialog.pack(); + dialog.setVisible(true); + } + catch (Exception e) { + JOptionPane.showMessageDialog(SemantGui.this, + "Error creating asy graph\n", + "Cannot create asy graph\n" + + e.getStackTrace(), + JOptionPane.ERROR_MESSAGE); + } + } +} diff --git a/src/main/java/parse/Loc.java b/src/main/java/parse/Loc.java index 933bacd..c78db94 100644 --- a/src/main/java/parse/Loc.java +++ b/src/main/java/parse/Loc.java @@ -1,64 +1,64 @@ -package parse; - -import java_cup.runtime.ComplexSymbolFactory.Location; -import java_cup.runtime.ComplexSymbolFactory.ComplexSymbol; -import java_cup.runtime.Symbol; - -public class Loc { - - public final Location left; - public final Location right; - - private Loc(Location left, Location right) { - this.left = left; - this.right = right; - } - - public static Loc loc() { - return loc(new Location(-1, -1)); - } - - public static Loc loc(Location left) { - return loc(left, left); - } - - public static Loc loc(Location left, Location right) { - return new Loc(left, right); - } - - public static Loc loc(Symbol symbol) { - return loc(new Location(symbol.left, symbol.right)); - } - - public static Loc loc(Symbol a, Symbol b) { - return loc(new Location(a.left, b.right)); - } - - public static Loc loc(ComplexSymbol symbol) { - return new Loc(symbol.getLeft(), symbol.getRight()); - } - - public static Loc loc(ComplexSymbol a, ComplexSymbol b) { - return new Loc(a.getLeft(), b.getRight()); - } - - @Override - public String toString() { - if (left.getUnit().equals("unknown") && right.getUnit().equals("unknown")) - return String.format("%d/%d-%d/%d", - left.getLine(), left.getColumn(), - right.getLine(), right.getColumn()); - else if (left.getUnit().equals(right.getUnit())) - return String.format("%s:%d/%d-%d/%d", - left.getUnit(), - left.getLine(), left.getColumn(), - right.getLine(), right.getColumn()); - else - return String.format("%s:%d/%d-%s:%d/%d", - left.getUnit(), - left.getLine(), left.getColumn(), - right.getUnit(), - right.getLine(), right.getColumn()); - } - -} +package parse; + +import java_cup.runtime.ComplexSymbolFactory.Location; +import java_cup.runtime.ComplexSymbolFactory.ComplexSymbol; +import java_cup.runtime.Symbol; + +public class Loc { + + public final Location left; + public final Location right; + + private Loc(Location left, Location right) { + this.left = left; + this.right = right; + } + + public static Loc loc() { + return loc(new Location(-1, -1)); + } + + public static Loc loc(Location left) { + return loc(left, left); + } + + public static Loc loc(Location left, Location right) { + return new Loc(left, right); + } + + public static Loc loc(Symbol symbol) { + return loc(new Location(symbol.left, symbol.right)); + } + + public static Loc loc(Symbol a, Symbol b) { + return loc(new Location(a.left, b.right)); + } + + public static Loc loc(ComplexSymbol symbol) { + return new Loc(symbol.getLeft(), symbol.getRight()); + } + + public static Loc loc(ComplexSymbol a, ComplexSymbol b) { + return new Loc(a.getLeft(), b.getRight()); + } + + @Override + public String toString() { + if (left.getUnit().equals("unknown") && right.getUnit().equals("unknown")) + return String.format("%d/%d-%d/%d", + left.getLine(), left.getColumn(), + right.getLine(), right.getColumn()); + else if (left.getUnit().equals(right.getUnit())) + return String.format("%s:%d/%d-%d/%d", + left.getUnit(), + left.getLine(), left.getColumn(), + right.getLine(), right.getColumn()); + else + return String.format("%s:%d/%d-%s:%d/%d", + left.getUnit(), + left.getLine(), left.getColumn(), + right.getUnit(), + right.getLine(), right.getColumn()); + } + +} diff --git a/src/main/java/semantic/SemanticHelper.java b/src/main/java/semantic/SemanticHelper.java index 7009f97..0723e0e 100644 --- a/src/main/java/semantic/SemanticHelper.java +++ b/src/main/java/semantic/SemanticHelper.java @@ -1,40 +1,40 @@ -package semantic; - -import error.CompilerError; - -import parse.Loc; -import types.Type; - -public interface SemanticHelper { - - static CompilerError typeMismatch(Loc loc, Type found, Type... expected) { - final StringBuilder builder = new StringBuilder(); - final int n = expected.length; - if (n > 0) { - builder.append(expected[0]); - if (n > 1) { - for (int i = 1; i < n - 2; i++) - builder.append(", ").append(expected[i]); - builder.append(" or ").append(expected[n - 1]); - } - } - return new CompilerError(loc, "type mismatch: found %s but expected %s", found, builder); - } - - static CompilerError undefined(Loc loc, String category, String name) { - return new CompilerError(loc, "undefined %s '%s'", category, name); - } - - static CompilerError notAFunction(Loc loc, String name) { - return new CompilerError(loc, "'%s' is not a function", name); - } - - static CompilerError tooFewArguments(Loc loc, String name) { - return new CompilerError(loc, "too few arguments in call to '%s'", name); - } - - static CompilerError tooMuchArguments(Loc loc, String name) { - return new CompilerError(loc, "too much arguments in call to '%s'", name); - } - -} +package semantic; + +import error.CompilerError; + +import parse.Loc; +import types.Type; + +public interface SemanticHelper { + + static CompilerError typeMismatch(Loc loc, Type found, Type... expected) { + final StringBuilder builder = new StringBuilder(); + final int n = expected.length; + if (n > 0) { + builder.append(expected[0]); + if (n > 1) { + for (int i = 1; i < n - 2; i++) + builder.append(", ").append(expected[i]); + builder.append(" or ").append(expected[n - 1]); + } + } + return new CompilerError(loc, "type mismatch: found %s but expected %s", found, builder); + } + + static CompilerError undefined(Loc loc, String category, String name) { + return new CompilerError(loc, "undefined %s '%s'", category, name); + } + + static CompilerError notAFunction(Loc loc, String name) { + return new CompilerError(loc, "'%s' is not a function", name); + } + + static CompilerError tooFewArguments(Loc loc, String name) { + return new CompilerError(loc, "too few arguments in call to '%s'", name); + } + + static CompilerError tooMuchArguments(Loc loc, String name) { + return new CompilerError(loc, "too much arguments in call to '%s'", name); + } + +} diff --git a/src/main/java/types/BOOL.java b/src/main/java/types/BOOL.java index cb848a2..240e1ed 100644 --- a/src/main/java/types/BOOL.java +++ b/src/main/java/types/BOOL.java @@ -1,14 +1,14 @@ -package types; - -public class BOOL extends Type { - - public static final BOOL T = new BOOL(); - - private BOOL() { - } - - @Override - public String toString() { - return "bool"; - } -} +package types; + +public class BOOL extends Type { + + public static final BOOL T = new BOOL(); + + private BOOL() { + } + + @Override + public String toString() { + return "bool"; + } +} diff --git a/src/main/java/types/FUNCTION.java b/src/main/java/types/FUNCTION.java index 4324891..81a1419 100644 --- a/src/main/java/types/FUNCTION.java +++ b/src/main/java/types/FUNCTION.java @@ -1,29 +1,29 @@ -package types; - -import javaslang.collection.List; - -public class FUNCTION extends Type { - - public Type result; - public List formals; - - public FUNCTION(Type result, List formals) { - this.result = result; - this.formals = formals; - } - - public FUNCTION(Type result, Type... formals) { - this(result, List.of(formals)); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("("); - formals.map(Type::toString).intersperse(","); - builder.append("->"); - builder.append(result.toString()); - return builder.toString(); - } - -} +package types; + +import javaslang.collection.List; + +public class FUNCTION extends Type { + + public Type result; + public List formals; + + public FUNCTION(Type result, List formals) { + this.result = result; + this.formals = formals; + } + + public FUNCTION(Type result, Type... formals) { + this(result, List.of(formals)); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("("); + formals.map(Type::toString).intersperse(","); + builder.append("->"); + builder.append(result.toString()); + return builder.toString(); + } + +} diff --git a/src/main/java/types/INT.java b/src/main/java/types/INT.java index af4cf00..abc75c4 100644 --- a/src/main/java/types/INT.java +++ b/src/main/java/types/INT.java @@ -1,14 +1,14 @@ -package types; - -public class INT extends Type { - - public static final INT T = new INT(); - - private INT() { - } - - @Override - public String toString() { - return "int"; - } -} +package types; + +public class INT extends Type { + + public static final INT T = new INT(); + + private INT() { + } + + @Override + public String toString() { + return "int"; + } +} diff --git a/src/main/java/types/REAL.java b/src/main/java/types/REAL.java index e4a7188..6863632 100644 --- a/src/main/java/types/REAL.java +++ b/src/main/java/types/REAL.java @@ -1,14 +1,14 @@ -package types; - -public class REAL extends Type { - - public static final REAL T = new REAL(); - - private REAL() { - } - - @Override - public String toString() { - return "real"; - } -} +package types; + +public class REAL extends Type { + + public static final REAL T = new REAL(); + + private REAL() { + } + + @Override + public String toString() { + return "real"; + } +} diff --git a/src/main/java/types/Type.java b/src/main/java/types/Type.java index 0abb24f..500bf84 100644 --- a/src/main/java/types/Type.java +++ b/src/main/java/types/Type.java @@ -1,33 +1,33 @@ -package types; - -import javaslang.collection.List; -import javaslang.collection.Tree; -import javaslang.collection.Tree.Node; -import javaslang.render.ToTree; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -public abstract class Type implements ToTree { - - @Override - public Node toTree() { - return Tree.of(toString()); - } - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); - } - - // Verify if this type can be coerced to the given type. In - // general one type can be coerced to another type if and only if the - // types are the same. - public boolean is(Type type) { - return type == this; - } - - // Verify if this type can be coerced to any of the given types. - public boolean is(Type... types) { - return List.of(types).exists(t -> this.is(t)); - } -} +package types; + +import javaslang.collection.List; +import javaslang.collection.Tree; +import javaslang.collection.Tree.Node; +import javaslang.render.ToTree; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +public abstract class Type implements ToTree { + + @Override + public Node toTree() { + return Tree.of(toString()); + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); + } + + // Verify if this type can be coerced to the given type. In + // general one type can be coerced to another type if and only if the + // types are the same. + public boolean is(Type type) { + return type == this; + } + + // Verify if this type can be coerced to any of the given types. + public boolean is(Type... types) { + return List.of(types).exists(t -> this.is(t)); + } +} diff --git a/src/main/java/types/UNIT.java b/src/main/java/types/UNIT.java index 8201ed9..1888c26 100644 --- a/src/main/java/types/UNIT.java +++ b/src/main/java/types/UNIT.java @@ -1,15 +1,15 @@ -package types; - -public class UNIT extends Type { - - public static final UNIT T = new UNIT(); - - private UNIT() { - } - - @Override - public String toString() { - return "unit"; - } - -} +package types; + +public class UNIT extends Type { + + public static final UNIT T = new UNIT(); + + private UNIT() { + } + + @Override + public String toString() { + return "unit"; + } + +} diff --git a/src/main/jflex/lexer.jflex b/src/main/jflex/lexer.jflex index 0e40df5..b4aa74c 100644 --- a/src/main/jflex/lexer.jflex +++ b/src/main/jflex/lexer.jflex @@ -1,99 +1,100 @@ -package parse; - -import static error.ErrorHelper.error; - -import java_cup.runtime.Symbol; -import java_cup.runtime.SymbolFactory; -import java_cup.runtime.ComplexSymbolFactory.Location; -import java_cup.runtime.ComplexSymbolFactory; - -%% - -%public -%final -%class Lexer -%implements SymbolConstants -%cupsym SymbolConstants -%cup -%line -%column - -%eofval{ - return tok(EOF); -%eofval} - -%ctorarg String unitName - -%init{ - this.unit = unitName; -%init} - -%{ - private String unit; - - private ComplexSymbolFactory complexSymbolFactory = new ComplexSymbolFactory(); - - public SymbolFactory getSymbolFactory() { - return complexSymbolFactory; - } - - // auxiliary methods to construct terminal symbols at current location - - private Location locLeft() { - return new Location(unit, yyline + 1, yycolumn + 1); - } - - private Location locRight() { - return new Location(unit, yyline + 1, yycolumn + 1 + yylength()); - } - - private Symbol tok(int type, String lexeme, Object value) { - return complexSymbolFactory.newSymbol(lexeme, type, locLeft(), locRight(), value); - } - - private Symbol tok(int type, Object value) { - return tok(type, yytext(), value); - } - - private Symbol tok(int type) { - return tok(type, null); - } -%} - -litint = [0-9]+ -litfloat1 = [0-9]+ "." [0-9]* -litfloat2 = [0-9]* "." [0-9]+ -litfloat3 = ({litint} | {litfloat1} | {litfloat2}) [eE] [+-]? {litint} -litreal = {litint} | {litfloat1} | {litfloat2} | {litfloat3} -litbool = true | false - -id = [a-zA-Z][a-zA-Z0-9_]* - -%% - -[ \t\f\n\r]+ { /* skip */ } - -{litint} { return tok(LITINT, yytext()); } -{litreal} { return tok(LITREAL, yytext()); } -{litbool} { return tok(LITBOOL, yytext()); } - -var { return tok(VAR); } -let { return tok(LET); } -in { return tok(IN); } - -{id} { return tok(ID, yytext().intern()); } - -"+" { return tok(PLUS); } -"-" { return tok(MINUS); } -"*" { return tok(TIMES); } -"/" { return tok(DIV); } -"&&" { return tok(AND); } -"||" { return tok(OR); } -"(" { return tok(LPAREN); } -")" { return tok(RPAREN); } -"," { return tok(COMMA); } -";" { return tok(SEMICOLON); } -":" { return tok(COLON); } -"=" { return tok(EQ); } - -. { throw error(Loc.loc(locLeft()), "unexpected char '%s'", yytext()); } +package parse; + +import static error.ErrorHelper.error; + +import java_cup.runtime.Symbol; +import java_cup.runtime.SymbolFactory; +import java_cup.runtime.ComplexSymbolFactory.Location; +import java_cup.runtime.ComplexSymbolFactory; + +%% + +%public +%final +%class Lexer +%implements SymbolConstants +%cupsym SymbolConstants +%cup +%line +%column + +%eofval{ + return tok(EOF); +%eofval} + +%ctorarg String unitName + +%init{ + this.unit = unitName; +%init} + +%{ + private String unit; + + private ComplexSymbolFactory complexSymbolFactory = new ComplexSymbolFactory(); + + public SymbolFactory getSymbolFactory() { + return complexSymbolFactory; + } + + // auxiliary methods to construct terminal symbols at current location + + private Location locLeft() { + return new Location(unit, yyline + 1, yycolumn + 1); + } + + private Location locRight() { + return new Location(unit, yyline + 1, yycolumn + 1 + yylength()); + } + + private Symbol tok(int type, String lexeme, Object value) { + return complexSymbolFactory.newSymbol(lexeme, type, locLeft(), locRight(), value); + } + + private Symbol tok(int type, Object value) { + return tok(type, yytext(), value); + } + + private Symbol tok(int type) { + return tok(type, null); + } +%} + +litint = [0-9]+ +litfloat1 = [0-9]+ "." [0-9]* +litfloat2 = [0-9]* "." [0-9]+ +litfloat3 = ({litint} | {litfloat1} | {litfloat2}) [eE] [+-]? {litint} +litreal = {litint} | {litfloat1} | {litfloat2} | {litfloat3} +litbool = true | false + +id = [a-zA-Z][a-zA-Z0-9_]* + +%% + +[ \t\f\n\r]+ { /* skip */ } + +{litint} { return tok(LITINT, yytext()); } +{litreal} { return tok(LITREAL, yytext()); } +{litbool} { return tok(LITBOOL, yytext()); } + +var { return tok(VAR); } +let { return tok(LET); } +in { return tok(IN); } + +{id} { return tok(ID, yytext().intern()); } + +"+" { return tok(PLUS); } +"-" { return tok(MINUS); } +"*" { return tok(TIMES); } +"/" { return tok(DIV); } +"&&" { return tok(AND); } +"||" { return tok(OR); } +"(" { return tok(LPAREN); } +")" { return tok(RPAREN); } +"," { return tok(COMMA); } +";" { return tok(SEMICOLON); } +":" { return tok(COLON); } +"=" { return tok(EQ); } +":=" { return tok(ASSIGN); } + +. { throw error(Loc.loc(locLeft()), "unexpected char '%s'", yytext()); } diff --git a/src/test/java/Test/SemantTest.java b/src/test/java/Test/SemantTest.java index dd734fe..d2523b4 100644 --- a/src/test/java/Test/SemantTest.java +++ b/src/test/java/Test/SemantTest.java @@ -1,92 +1,92 @@ -package Test; - -import absyn.Exp; -import env.Env; -import error.CompilerError; -import java_cup.runtime.Symbol; -import org.assertj.core.api.JUnitSoftAssertions; -import org.junit.Rule; -import org.junit.Test; -import parse.Lexer; -import parse.Parser; -import types.*; - -import java.io.IOException; -import java.io.StringReader; - -public class SemantTest { - - private Type runSemantic(String input) throws Exception { - Lexer lexer = new Lexer(new StringReader(input), "unknown"); - Parser parser = new Parser(lexer); - Symbol program = parser.parse(); - Exp parseTree = (Exp) program.value; - return parseTree.semantic(new Env()); - } - - private void trun(String input, Type type) { - try { - softly.assertThat(runSemantic(input)) - .as("%s", input) - .isEqualTo(type); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - private void erun(String input, String message) throws IOException { - softly.assertThatThrownBy(() -> runSemantic(input)) - .as("%s", input) - .isInstanceOf(CompilerError.class) - .hasToString(message); - } - - @Rule - public final JUnitSoftAssertions softly = new JUnitSoftAssertions(); - - @Test - public void testLiterals() throws Exception { - trun("true", BOOL.T); - trun("123", INT.T); - trun("12.34", REAL.T); - } - - @Test - public void testFunctionCall() throws Exception { - erun("fat(9)", - "error.CompilerError: 1/1-1/7 undefined function 'fat'"); - erun("fat(g(), h())", - "error.CompilerError: 1/5-1/8 undefined function 'g'"); - trun("print_int(123)", - UNIT.T); - erun("print_int(true)", - "error.CompilerError: 1/11-1/15 type mismatch: found bool but expected int"); - erun("print_int(123, true, f())", - "error.CompilerError: 1/22-1/25 undefined function 'f'"); - erun("print_int()", - "error.CompilerError: 1/1-1/12 too few arguments in call to 'print_int'"); - } - - @Test - public void testSequence() throws Exception { - trun("()", UNIT.T); - trun("(true)", BOOL.T); - trun("(print_int(23); 2.3)", REAL.T); - } - - @Test - public void testSimpleVariableAndLet() throws Exception { - erun("x", - "error.CompilerError: 1/1-1/2 undefined variable 'x'"); - trun("let var x: int = 10 in x", - INT.T); - trun("let var x = 0.56 in x", - REAL.T); - erun("let var x: int = 3.4 in x", - "error.CompilerError: 1/18-1/21 type mismatch: found real but expected int"); - erun("(let var x = 5 in print_int(x); x)", - "error.CompilerError: 1/33-1/34 undefined variable 'x'"); - } - -} +package Test; + +import absyn.Exp; +import env.Env; +import error.CompilerError; +import java_cup.runtime.Symbol; +import org.assertj.core.api.JUnitSoftAssertions; +import org.junit.Rule; +import org.junit.Test; +import parse.Lexer; +import parse.Parser; +import types.*; + +import java.io.IOException; +import java.io.StringReader; + +public class SemantTest { + + private Type runSemantic(String input) throws Exception { + Lexer lexer = new Lexer(new StringReader(input), "unknown"); + Parser parser = new Parser(lexer); + Symbol program = parser.parse(); + Exp parseTree = (Exp) program.value; + return parseTree.semantic(new Env()); + } + + private void trun(String input, Type type) { + try { + softly.assertThat(runSemantic(input)) + .as("%s", input) + .isEqualTo(type); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + private void erun(String input, String message) throws IOException { + softly.assertThatThrownBy(() -> runSemantic(input)) + .as("%s", input) + .isInstanceOf(CompilerError.class) + .hasToString(message); + } + + @Rule + public final JUnitSoftAssertions softly = new JUnitSoftAssertions(); + + @Test + public void testLiterals() throws Exception { + trun("true", BOOL.T); + trun("123", INT.T); + trun("12.34", REAL.T); + } + + @Test + public void testFunctionCall() throws Exception { + erun("fat(9)", + "error.CompilerError: 1/1-1/7 undefined function 'fat'"); + erun("fat(g(), h())", + "error.CompilerError: 1/5-1/8 undefined function 'g'"); + trun("print_int(123)", + UNIT.T); + erun("print_int(true)", + "error.CompilerError: 1/11-1/15 type mismatch: found bool but expected int"); + erun("print_int(123, true, f())", + "error.CompilerError: 1/22-1/25 undefined function 'f'"); + erun("print_int()", + "error.CompilerError: 1/1-1/12 too few arguments in call to 'print_int'"); + } + + @Test + public void testSequence() throws Exception { + trun("()", UNIT.T); + trun("(true)", BOOL.T); + trun("(print_int(23); 2.3)", REAL.T); + } + + @Test + public void testSimpleVariableAndLet() throws Exception { + erun("x", + "error.CompilerError: 1/1-1/2 undefined variable 'x'"); + trun("let var x: int = 10 in x", + INT.T); + trun("let var x = 0.56 in x", + REAL.T); + erun("let var x: int = 3.4 in x", + "error.CompilerError: 1/18-1/21 type mismatch: found real but expected int"); + erun("(let var x = 5 in print_int(x); x)", + "error.CompilerError: 1/33-1/34 undefined variable 'x'"); + } + +} diff --git a/tests/test-lexer-01.eplan b/tests/test-lexer-01.eplan index 03e1a60..3c8e13a 100644 --- a/tests/test-lexer-01.eplan +++ b/tests/test-lexer-01.eplan @@ -1,3 +1,3 @@ -12 * - (453.2 - 140.300) / - 2 +12 * + (453.2 - 140.300) / + 2