diff --git a/.gitignore b/.gitignore index 4acafde1..8875552e 100644 --- a/.gitignore +++ b/.gitignore @@ -395,10 +395,10 @@ dmypy.json ### VisualStudioCode ### .vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json +.vscode/settings.json +.vscode/tasks.json +.vscode/launch.json +.vscode/extensions.json ### VisualStudioCode Patch ### # Ignore all local history of files diff --git a/Informe/informe.pdf b/Informe/informe.pdf new file mode 100644 index 00000000..7c47606e Binary files /dev/null and b/Informe/informe.pdf differ diff --git a/Informe/informe.sty b/Informe/informe.sty new file mode 100644 index 00000000..8f13fd78 --- /dev/null +++ b/Informe/informe.sty @@ -0,0 +1,309 @@ +% +% File: Macros for Journal of Machine Learning Research +% Very minor modification of macros for Journal of Artificial +% Intelligence Research (jair.sty) +% Last edited October 9, 2000 by Leslie Pack Kaelbling +% Last edited January 23, 2001 by Alex J. Smola (we should set up RCS or CVS) +% Last edited March 29, 2004 Erik G. Learned-Miller +% The name of this file should follow the article document +% type, e.g. \documentstyle[jmlr]{article} + +% Copied and edited from similar file for Machine Learning Journal. +% Original Author: Jeff Schlimmer +% Edited by: Kevin Thompson, Martha Del Alto, Helen Stewart, Steve Minton \& Pandu Nayak. +% Last edited: Mon May 3 20:40:00 1993 by kthompso (Kevin Thompson) on muir + +\typeout{Document Style `informe' -- Febrero 2013.} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% REQUIRED PACKAGES +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\RequirePackage[spanish,english]{babel} +\RequirePackage{epsfig} +\RequirePackage{amssymb} +\RequirePackage{graphicx} +\RequirePackage[margin=1in]{geometry} +\RequirePackage[utf8]{inputenc} +%\RequirePackage[stable]{footmisc} + +\bibliographystyle{plain} +\renewcommand\shorthandsspanish{} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% P A G E S I Z E +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Change the overall width of the page. If these parameters are +% changed, they will require corresponding changes in the +% maketitle section. +% + +\geometry{margin=2cm} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% S E C T I O N S +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Definitions for nicer (?) sections, etc., ideas from Pat Langley. +% Numbering for sections, etc. is taken care of automatically. + +\def\@startsiction#1#2#3#4#5#6{\if@noskipsec \leavevmode \fi + \par \@tempskipa #4\relax + \@afterindenttrue + \ifdim \@tempskipa <\z@ \@tempskipa -\@tempskipa \@afterindentfalse\fi + \if@nobreak \everypar{}\else + \addpenalty{\@secpenalty}\addvspace{\@tempskipa}\fi \@ifstar + {\@ssect{#3}{#4}{#5}{#6}}{\@dblarg{\@sict{#1}{#2}{#3}{#4}{#5}{#6}}}} + +\def\@sict#1#2#3#4#5#6[#7]#8{\ifnum #2>\c@secnumdepth + \def\@svsec{}\else + \refstepcounter{#1}\edef\@svsec{\csname the#1\endcsname}\fi + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@ + \begingroup #6\relax + \@hangfrom{\hskip #3\relax\@svsec.\hskip 0.1em} + {\interlinepenalty \@M #8\par} + \endgroup + \csname #1mark\endcsname{#7}\addcontentsline + {toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi + #7}\else + \def\@svsechd{#6\hskip #3\@svsec #8\csname #1mark\endcsname + {#7}\addcontentsline + {toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi + #7}}\fi + \@xsect{#5}} + +\def\@sect#1#2#3#4#5#6[#7]#8{\ifnum #2>\c@secnumdepth + \def\@svsec{}\else + \refstepcounter{#1}\edef\@svsec{\csname the#1\endcsname\hskip 0.5em }\fi + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@ + \begingroup #6\relax + \@hangfrom{\hskip #3\relax\@svsec}{\interlinepenalty \@M #8\par} + \endgroup + \csname #1mark\endcsname{#7}\addcontentsline + {toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi + #7}\else + \def\@svsechd{#6\hskip #3\@svsec #8\csname #1mark\endcsname + {#7}\addcontentsline + {toc}{#1}{\ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}\fi + #7}}\fi + \@xsect{#5}} + +\def\thesection {\arabic{section}} +\def\thesubsection {\thesection.\arabic{subsection}} +\def\section{\@startsiction{section}{1}{\z@}{-0.24in}{0.10in} + {\large\bf\raggedright}} +\def\subsection{\@startsection{subsection}{2}{\z@}{-0.20in}{0.08in} + {\normalsize\bf\raggedright}} +\def\subsubsection{\@startsection{subsubsection}{3}{\z@}{-0.18in}{0.08in} + {\normalsize\sc\raggedright}} +\def\paragraph{\@startsiction{paragraph}{4}{\z@}{1.5ex plus + 0.5ex minus .2ex}{-1em}{\normalsize\bf}} +\def\subparagraph{\@startsiction{subparagraph}{5}{\z@}{1.5ex plus + 0.5ex minus .2ex}{-1em}{\normalsize\bf}} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% F O O T N O T E S +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Change the size of the footnote rule +% +% \renewcommand{\footnoterule}{\vspace{10pt}\hrule width 0mm} + +\long\def\@makefntext#1{\@setpar{\@@par\@tempdima \hsize + \advance\@tempdima-15pt\parshape \@ne 15pt \@tempdima}\par + \parindent 2em\noindent \hbox to \z@{\hss{\@thefnmark}. \hfil}#1} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% A B S T R A C T +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% use \begin{abstract} .. \end{abstract} for abstracts. +\renewenvironment{abstract} +{\centerline{\large\bf Resumen}\vspace{0.7ex}% + \bgroup\leftskip 20pt\rightskip 20pt\small\noindent}% +{\par\egroup\vskip 0.25ex} + +\newenvironment{enabstract} +{\centerline{\large\bf \\Abstract}\vspace{0.7ex}% + \bgroup\leftskip 20pt\rightskip 20pt\small\noindent}% +{\par\egroup\vskip 0.25ex} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% KEYWORDS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% use \begin{keywords} .. \end{keywords} for keywordss. +\newenvironment{keywords} +{\bgroup\leftskip 20pt\rightskip 20pt \small\noindent{\bf \\Palabras Clave:} }% +{\par\egroup\vskip 0.25ex} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% TEMAS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Use \begin{topics} .. \end{topics} para los temas. +\newenvironment{topics} +{\bgroup\leftskip 20pt\rightskip 20pt \small\noindent{\bf Tema:} }% +{\par\egroup\vskip 0.25ex} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% FIRST PAGE, TITLE, AUTHOR +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Author information can be set in various styles: +% For several authors from the same institution: +% \author{Author 1 \and ... \and Author n \\ +% \addr{Address line} \\ ... \\ \addr{Address line}} +% if the names do not fit well on one line use +% Author 1 \\ {\bf Author 2} \\ ... \\ {\bf Author n} \\ +% To start a seperate ``row'' of authors use \AND, as in +% \author{Author 1 \\ \addr{Address line} \\ ... \\ \addr{Address line} +% \AND +% Author 2 \\ \addr{Address line} \\ ... \\ \addr{Address line} \And +% Author 3 \\ \addr{Address line} \\ ... \\ \addr{Address line}} + +% Title stuff, borrowed in part from aaai92.sty + +\newlength\aftertitskip \newlength\beforetitskip +\newlength\interauthorskip \newlength\aftermaketitskip + +%% Changeable parameters. +\setlength\aftertitskip{0.1in plus 0.2in minus 0.2in} +\setlength\beforetitskip{0.05in plus 0.08in minus 0.08in} +\setlength\interauthorskip{0.08in plus 0.1in minus 0.1in} +\setlength\aftermaketitskip{0.3in plus 0.1in minus 0.1in} + +%% overall definition of maketitle, @maketitle does the real work +\def\maketitle{\par + \begingroup + \def\thefootnote{\fnsymbol{footnote}} + \def\@makefnmark{\hbox to 0pt{$^{\@thefnmark}$\hss}} + \@maketitle \@thanks + \endgroup +\setcounter{footnote}{0} + \let\maketitle\relax \let\@maketitle\relax + \gdef\@thanks{}\gdef\@author{}\gdef\@title{}\let\thanks\relax} + +\def\@startauthor{\noindent \normalsize\bf} +\def\@endauthor{} +\def\@starttutors{\noindent \small {\bf Tutor(es):~}} +\def\@endtutors{\normalsize} +\def\@maketitle{\vbox{\hsize\textwidth + \linewidth\hsize \vskip \beforetitskip + {\begin{center} \Large\bf \@title \par \end{center}} \vskip \aftertitskip + {\def\and{\unskip\enspace{\rm y}\enspace}% + \def\addr{\small\it}% + \def\email{\hfill\small\sc}% + \def\name{\normalsize\bf}% + \def\AND{\@endauthor\rm\hss \vskip \interauthorskip \@startauthor} + \@startauthor \@author \@endauthor} + + \vskip \aftermaketitskip + \noindent \@starttutors \@tutors \@endtutors + \vskip \aftermaketitskip +}} + +\newcommand\kernelmachines{(for {\sc{http://www.kernel-machines.org}})} +\def\tutors#1{\gdef\@tutors{#1}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +%%% Pagestyle +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% Defines the pagestyle for the title page. +%% Usage: \jcematcomheading{2009}{1-15}{Mat y Com}{Jane Q. Public and A. U. Thor} +%% \jcematcomheading{year}{pages}{Tribunal}{authors} + +\def\firstpageno#1{\setcounter{page}{#1}} + +\def\jcematcomheading#1#2#3{\def\ps@jmlrtps{\let\@mkboth\@gobbletwo% +\def\@oddhead{\scriptsize Compilación MatCom #1 % +\hfill Páginas #2}% +\def\@oddfoot{\scriptsize \copyright #1 #3. \hfill}% +\def\@evenhead{}\def\@evenfoot{}}% +\thispagestyle{jmlrtps}} + +%% Defines the pagestyle for the rest of the pages +%% Usage: \ShortHeadings{Minimizing Conflicts}{Minton et al} +%% \ShortHeadings{short title}{short authors} + +\def\ShortHeadings#1#2{\def\ps@jmlrps{\let\@mkboth\@gobbletwo% +\def\@oddhead{\hfill {\small\sc #1} \hfill}% +\def\@oddfoot{\hfill \small\rm \thepage \hfill}% +\def\@evenhead{\hfill {\small\sc #2} \hfill}% +\def\@evenfoot{\hfill \small\rm \thepage \hfill}}% +\pagestyle{jmlrps}} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% MISCELLANY +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Define macros for figure captions and table titles + +% Figurecaption prints the caption title flush left. +% \def\figurecaption#1#2{\noindent\hangindent 42pt +% \hbox to 36pt {\sl #1 \hfil} +% \ignorespaces #2} +% \def\figurecaption#1#2{\noindent\hangindent 46pt +% \hbox to 41pt {\small\sl #1 \hfil} +% \ignorespaces {\small #2}} +\def\figurecaption#1#2{\noindent\hangindent 40pt + \hbox to 36pt {\small\sl #1 \hfil} + \ignorespaces {\small #2}} +% Figurecenter prints the caption title centered. +\def\figurecenter#1#2{\centerline{{\sl #1} #2}} +\def\figurecenter#1#2{\centerline{{\small\sl #1} {\small #2}}} + +% +% Allow ``hanging indents'' in long captions +% +\long\def\@makecaption#1#2{ + \vskip 10pt + \setbox\@tempboxa\hbox{#1: #2} + \ifdim \wd\@tempboxa >\hsize % IF longer than one line: + \begin{list}{#1:}{ + \settowidth{\labelwidth}{#1:} + \setlength{\leftmargin}{\labelwidth} + \addtolength{\leftmargin}{\labelsep} + }\item #2 \end{list}\par % Output in quote mode + \else % ELSE center. + \hbox to\hsize{\hfil\box\@tempboxa\hfil} + \fi} + + +% Define strut macros for skipping spaces above and below text in a +% tabular environment. +\def\abovestrut#1{\rule[0in]{0in}{#1}\ignorespaces} +\def\belowstrut#1{\rule[-#1]{0in}{#1}\ignorespaces} + +% Acknowledgments +\long\def\acks#1{\vskip 0.3in\noindent{\large\bf Agradecimientos}\vskip 0.2in +\noindent #1} + +% Research Note +\long\def\researchnote#1{\noindent {\LARGE\it Research Note} #1} + +\renewcommand{\appendix}{\par + \setcounter{section}{0} + \setcounter{subsection}{0} + \def\thesection{\Alph{section}} +\def\section{\@ifnextchar*{\@startsiction{section}{1}{\z@}{-0.24in}{0.10in}% + {\large\bf\raggedright}}% +{\@startsiction{section}{1}{\z@}{-0.24in}{0.10in} + {\large\bf\raggedright Appendix\ }}}} + + + + diff --git a/Informe/informe.tex b/Informe/informe.tex new file mode 100644 index 00000000..dfbcb62b --- /dev/null +++ b/Informe/informe.tex @@ -0,0 +1,333 @@ +%=================================================================================== +% JORNADA CIENTÍFICA ESTUDIANTIL - MATCOM, UH +%=================================================================================== +% Esta plantilla ha sido diseñada para ser usada en los artículos de la +% Jornada Científica Estudiantil, MatCom. +% +% Por favor, siga las instrucciones de esta plantilla y rellene en las secciones +% correspondientes. +% +% NOTA: Necesitará el archivo 'jcematcom.sty' en la misma carpeta donde esté este +% archivo para poder utilizar esta plantila. +%=================================================================================== + + + +%=================================================================================== +% PREÁMBULO +%----------------------------------------------------------------------------------- +\documentclass[a4paper,10pt,twocolumn]{article} + +%=================================================================================== +% Paquetes +%----------------------------------------------------------------------------------- +\usepackage{amsmath} +\usepackage{amsfonts} +\usepackage{amssymb} +\usepackage{informe} +\usepackage[utf8]{inputenc} +\usepackage{listings} +\usepackage[pdftex]{hyperref} +%----------------------------------------------------------------------------------- +% Configuración +%----------------------------------------------------------------------------------- +\hypersetup{colorlinks,% + citecolor=black,% + filecolor=black,% + linkcolor=black,% + urlcolor=blue} + +%=================================================================================== + + + +%=================================================================================== +% Presentacion +%----------------------------------------------------------------------------------- +% Título +%----------------------------------------------------------------------------------- +\title{Informe de Entrega CoolCompiler 2020} + +%----------------------------------------------------------------------------------- +% Autores +%----------------------------------------------------------------------------------- +\author{\\ + \name Jorge Daniel Valle Díaz \email \href{mailto:jorge.valle@estudiantes.matcom.uh.cu}{jorge.valle@estudiantes.matcom.uh.cu} + \\ \addr Grupo C412 \AND + \name Leonel Alejandro Garc\'ia L\'opez \email \href{mailto:l.garcia3@estudiantes.matcom.uh.cu}{l.garcia3@estudiantes.matcom.uh.cu} + \\ \addr Grupo C412 \AND + \name Roberto Marti Cede\~no \email \href{mailto:r.marti@estudiantes.matcom.uh.cu}{r.marti@estudiantes.matcom.uh.cu} + \\ \addr Grupo C412 +} + +%----------------------------------------------------------------------------------- +% Tutores +%----------------------------------------------------------------------------------- +\tutors{\\ +Msc. Alejandro Piad Morffis, \emph{Facultad de Matemática y Computación, Universidad de La Habana}} + +%----------------------------------------------------------------------------------- +% Headings +%----------------------------------------------------------------------------------- +\jcematcomheading{\the\year}{1-\pageref{end}}{Jorge Daniel Valle Díaz, Leonel Alejandro Garc\'ia L\'opez, Roberto Marti Cede\~no} + +%----------------------------------------------------------------------------------- +\ShortHeadings{Ejemplo JCE}{Autores} +%=================================================================================== + + + +%=================================================================================== +% DOCUMENTO +%----------------------------------------------------------------------------------- +\begin{document} + +%----------------------------------------------------------------------------------- +% NO BORRAR ESTA LINEA! +%----------------------------------------------------------------------------------- +\twocolumn[ +%----------------------------------------------------------------------------------- + +\maketitle + +%=================================================================================== +% Resumen y Abstract +%----------------------------------------------------------------------------------- +\selectlanguage{spanish} % Para producir el documento en Español + +%----------------------------------------------------------------------------------- +% Resumen en Español +%----------------------------------------------------------------------------------- + + +\vspace{0.5cm} + +%----------------------------------------------------------------------------------- +% Palabras clave +%----------------------------------------------------------------------------------- + +%----------------------------------------------------------------------------------- +% Temas +%----------------------------------------------------------------------------------- +\begin{topics} + Compilación, Cool Language. +\end{topics} + + +%----------------------------------------------------------------------------------- +% NO BORRAR ESTAS LINEAS! +%----------------------------------------------------------------------------------- +\vspace{0.8cm} +] +%----------------------------------------------------------------------------------- + + +%=================================================================================== + +%=================================================================================== +% Introducción +%----------------------------------------------------------------------------------- +\section{Introducción}\label{sec:intro} +%----------------------------------------------------------------------------------- + El siguiente trabajo representa el informe sobre la confección del compilador. Para la confección del mismo se empleó el lenguaje python de programación. El proyecto se dividió en varias etapas: Análisis lexicográfico, sintáctico, semántico, código intermedio y generación de código de máquina. Es importante destacar que se reutilizaron en la medida de lo posible los archivos de clase práctica y los proyectos realizados en el curso previo de la asignatura. + +%=================================================================================== + + + +%=================================================================================== +% Desarrollo +%----------------------------------------------------------------------------------- +\section{Lexer}\label{sec:dev} +%----------------------------------------------------------------------------------- + En la fase de análisis lexicográfico se empleó la biblioteca ply, en especial su módulo lex. + Salvo en el caso de las cadenas de caracteres y los comentarios multi-línea, el resto de los tokens fueron procesados mediante expresiones regulares. Para el caso de las cadenas de caracteres y los comentarios multi-líneas se emplearon estados especiales exclusivos. + +\section{Parser} + La fase de análisis sintáctico ha sido una de las fases mas controversiales a la hora de la realización del proyecto. Se empleó en una primera fase el parser LR1 tomado de clase práctica y los proyectos previos de la asignatura. La gramática que se definió durante la primera entrega del proyecto contenía ambigüedades, las cuales fueron detectada comprobando las pruebas correspondientes a la parte de semántica. + + Finalmente el equipo decisión emplear el módulo \textit{Yacc} de \textit{ply} para definir la gramática y evitar las ambigüedades que se desprendían de la implementación inicial. + + La gram\'atica resultante result\'o trivial hasta el punto de definir la estructura de las expresiones, para estas \'ultimas con la ayuda de \textit{ply} se estableci\'o una prioridad entre los operadores quedando de la siguiente forma: + + \begin{table}[h] + \centering + \begin{tabular}{|c|c|} + \hline + Asociatividad & s\'imbolo \\ + \hline + derecha & $<-$\\ + \hline + derecha & $not$\\ + \hline + - & $<,<=,=$ \\ + \hline + izquierda & $+,-$\\ + \hline + izquierda & $*,/$\\ + \hline + derecha & $isvoid$\\ + \hline + derecha & $compl$\\ + \hline + izquierda & $@$\\ + \hline + izquierda & $.$\\ + \hline + \end{tabular} + \caption{Operadores ordenados seg\'un la precedencia desde el menos prioritario.} + + \end{table} + + + Gram\'atica de expresiones: + \textit{ + \begin{itemize} + \item[$E$] $\rightarrow$ id $<-$ E $|$ OP + \item[$OP$] $ \rightarrow$ OP $<$ OP $|$ OP $<=$ OP $+$ OP $=$ OP $|$ + \item[] $ \rightarrow $ OP $-$ OP $|$ OP $+$ OP $|$ OP $*$ OP $| $ + \item[] $ \rightarrow $ OP $/$ OP $|$ OP $*$ OP $|$ + \item[] $ \rightarrow BS$ + \item[$BS$] $ \rightarrow $SA $@$ type $.$ \textbf{FunctionCall} $|$ + \item[] $ \rightarrow SA$ + \item[$SA$] $ \rightarrow $ $($ E $)$ $|$ + \item[] $ \rightarrow$ SA $.$ \textbf{FunctionCall} $|$ \textbf{FunctionCall} $|$ + \item[] $ \rightarrow $ not OP $|$ isvoid OP $|$ compl OP $|$ + \item[] $ \rightarrow $ let \textbf{LetVariableDeclarations} in E $|$ + \item[] $ \rightarrow $ case E of \textbf{CaseActions} esac $|$ + \item[] $ \rightarrow $ if E then E else E fi $|$ + \item[] $ \rightarrow $ while E loop E pool $|$ + \item[] $ \rightarrow $ A + \item[$A$] $ \rightarrow$ int $|$ string $|$ bool $|$ id $|$ + \item[] $ \rightarrow $ new type $|$ \{ \textbf{ExpressionsList} \} + \end{itemize}} + + + + + +\section{Análisis Semántico} + + La fase de análisis semántico se compuso por 3 recorridos del árbol de sintaxis abstracta derivado de la fase de análisis sintáctico que siguen el patrón visitor. + + \begin{description} + \item [Recolector de tipos:] Primer recorrido del ast, en el cual se conforman los tipos nativos y los definidos en el archivo de código a procesar. En este mismo recorrido también se detectan los problemas relacionados con la herencia cíclica. + \item [Constructor de tipos:] Segundo recorrido del ast, en el cual se construyen los tipos, se definen sus métodos y atributos. + \item [Verificador de tipos:] Tercer y ultimo recorrido del ast, en el cual se verifica la estructura de cada uno de los nodos del ast, este recorrido es el que mas abarca las reglas semánticas del lenguaje Cool. + \end{description} + +\section{Código intermedio y código de máquina} + +El equipo decidió realizar una representación intermedia del lenguaje Cool antes de pasar a la generación de código de máquina. Para ello se definieron 2 nuevos recorridos a árboles de sintaxis abstracta, uno para llevar de Cool a CIL y otro para llevar CIL a MIPS. + +\subsection{Código intermedio} + + Del AST obtenido en las fases anteriores, en un cuarto recorrido se realizó una transformación hacia un AST de CIL que facilitara que el comportamiento obtenido en COOL sea más factible a un representación en MIPS. + + + Es también en esta fase donde se da por fin una implementación real a los tipos y + funciones básicas definidas por el lenguaje. Estas hacen uso de nodos especiales + del AST que solo son instanciadas para su uso desde COOL a través de las funciones + básicas. Ejemplo son los métodos para la entrada y salida de datos brindada por la + clase IO . Con estas estructuras definidas en el AST de CIL , durante la traducción a + MIPS , ellas serán generadas automáticamente. + + Aquí existió una vez más apoyo en los elementos de clase practica, al contar con un transpliador base para definir todas la convenciones tomadas, asi como contener los métodos necesarios para dicha conversión. + En esta fase surgió la necesidad de resolver un conjunto de especificaciones como son: + \begin{itemize} + \item \textbf{Relacionado a la herencia} Mantenemos como tipos de CIL como el conjunto de atributos de los respectivos en Cool pero con los de sus antecesores en la jerarqu\'ia de tipos(los m\'etodos y la tabla virtual queda para resolverse en MIPS) + \item \textbf{De los tipos por valor} El problema de los tipos por valor Int y Bool, y de los Strings como casos especiales, al ser usados como un objeto por referencia. Para esto se definió una representación en memorias para los casos en + que esto ocurriera. Todos estos tipos cuando fuera necesario tratarlos como objetos + por referencias, para por ejemplo acceder a las funciones heredadas de la clase + Object o las propiamente definidas por el tipo String , serían encapsulados en + instancias similares a los otros tipos, la cual contaría con un atributo value en el cual + se almacenaría el valor real de los mismos. + \item \textbf{Inicializaci\'on de atributos} Una de las especificaciones que se tuvo en cuenta para la generación de CIL fue la inicialización + de los atributos, tanto los heredados como los propios de la clase. Cuando se crea una instancia + de una clase se deben inicializar todos sus atributos con su expresión inicial, si tienen alguna; + en otro caso se usa su expresión por defecto. Con el objetivo de lograr esto se creó para cada + tipo un constructor, cuyo cuerpo consiste en un bloque, dándole un valor a cada uno de sus + atributos. Este es llamado cada vez que se instancia un tipo. + \item \textbf{Para las estructuras \textit{CaseOf}} de Cool realizamos un ordenamiento (dicho ordenamiento fue realizado de acuerdo a la profundidad de los tipos en la jerarqu\'ias, desde el m\'as espec\'ifico, hasta el más cercano a \textit{Object}) de los \textit{case actions} para realizar un \textit{matching} no iterativo y a partir del primer tipo presente en la jerarqu\'ia del objeto resultante de la expresi\'on del case. + Luego esta lista que llamamos \textbf{CaseActionExpressions} se extiende de manera ordenada para a\~nadir los tipos más espec\'ificos de los que se encontraban originalmente que a su vez como expresi\'on a realizar ser\'ia la mismo que el ancestro del que extendió, quedando una lista con bloques de case donde antes solo una opci\'on (conservando el orden anterior pero solo por bloques), de forma tal que en tiempo de ejecuci\'on el primer \textit{matching} fuese el correcto a realizar. + \end{itemize} + + \subsection{Código de máquina} + \'Ultimo recorrido, en este caso del árbol de sintaxis de representación intermedia. Mediante el cual se genera el código a ejecutar en el microprocesador con arquitectura MIPS. Es en este recorrido donde se crean los datos y la representación en memoria que sustentan el sitema de tipos de Cool. + + +\section{Representación y trabajo con la memoria} + +El equipo se decidió por una arquitectura en memoria que tiene por un lado la representación física del objeto con sus atributos y por otro una tabla de métodos virtuales global, la cual contiene todas las referencias a todas las implementaciones concretas de los métodos de las clases. + +\subsection{Representación en memoria} + +A continuación en la tabla \ref{fig:memory} presentamos en esquema seguido en memoria de una clase de Cool bajo la solución propuesta. + +El identificador de la clase se emplea además de su función básica para la comparación entre clases. El tamaño en memoria de la clase se emplea tanto para la copia como para el tamaño en bytes a reservar. La referencia al nombre de la clase representa la etiqueta correspondiente al nombre de la clase que representa la instancia en memoria y se emplea principalmente para los llamados al método typename. El desplazamiento representa la posición de la etiqueta correspondiente al primer método de la tabla virtual que corresponde a la clase que se tiene en cuestión. Finalizando, se encuentran, si existen, los atributos de la clase. + +\begin{table}[h] + \centering + \begin{tabular}{|c|} + \hline + Identificador de la clase \\ + \hline + Tamaño en memoria de la clase \\ + \hline + Referencia al nombre de la clase \\ + \hline + Desplazamiento en la tabla virtual \\ + \hline + Atributo 1 \\ + \hline + Atributo 2 \\ + \hline + ... \\ + \hline + Atributo n \\ + \hline + \end{tabular} + \caption{Distribución en memoria de una clase de Cool.} + \label{fig:memory} + +\end{table} + +\subsection{Tabla de métodos virtuales} + +Para dar solución al problema del ligamiento dinámico que resulta de la herencia se ideó la construcción de una tabla de métodos virtuales global. La tabla contiene todos los métodos correspondientes a todas las clases que se generan a partir de un programa en Cool. Una posible tabla virtual de un programa en Cool tendría una estructura como la siguiente: + +\newpage + +\begin{table}[h] + \centering + \begin{tabular}{|c|} + \hline + Método 1 de la clase 1 \\ + \hline + Método 2 de la clase 1 \\ + \hline + Método 1 de la clase 2 \\ + \hline + Método 1 de la clase 3 \\ + \hline + ... \\ + \hline + Método p de la clase n \\ + \hline + \end{tabular} + \caption{Distribución en memoria de la tabla de métodos virtuales.} + \label{fig:vtable} + +\end{table} + +La principal idea detrás de la tabla radica en la imposibilidad de tener toda la información de tipos en tiempo de compilación, el ligamiento de cada clase con su implementación de un método particular se deja para tiempo de ejecución. + +Cada clase se construye siguiendo el mismo patrón, de forma tal de que en el recorrido de generación de código se conocen todos los métodos y todos los atributos de cada clase y lo más importante: Dadas dos clases A y B, si A desciende de B o B de A, los atributos y métodos de A y B comunes aparecen en el mismo orden tanto en la tabla como en su espacio en memoria de cada instancia. + +Esta convención permitió que si una clase T tiene un tipo estático P en tiempo de compilación, pero realmente en ejecución tiene un tipo dinámico J, y J desciende de T, cualquier implementación de los métodos de T en J comparte el mismo orden en la tabla virtual. Por lo que conociendo el tipo estático y llamando al método correspondiente en la tabla virtual al tipo T, se esta llamando realmente al método de T que J sobrescribió. + +\label{end} + +\end{document} + +%=================================================================================== diff --git a/doc/Readme.md b/doc/Readme.md index 402477c8..505e1caf 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -4,9 +4,9 @@ **Nombre** | **Grupo** | **Github** --|--|-- -Nombre1 Apellido1 Apellido2 | C4xx | [@github_user](https://github.com/) -Nombre2 Apellido1 Apellido2 | C4xx | [@github_user](https://github.com/) -Nombre3 Apellido1 Apellido2 | C4xx | [@github_user](https://github.com/) +Leonel Alejandro García López | C412 | [@stdevlag](https://github.com/stdevlag) +Jorge Daniel Valle Díaz | C411 | [@thenai310](https://github.com/thenai310) +Roberto Marti Cedeño | C412 | [@rmarticedeno](https://github.com/rmarticedeno) ## Readme diff --git a/requirements.txt b/requirements.txt index 9eb0cad1..5a914fd8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ pytest pytest-ordering +ply \ No newline at end of file diff --git a/src/coolc.sh b/src/coolc.sh index 3088de4f..7493a037 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -4,8 +4,10 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2019: Nombre1, Nombre2, Nombre3" # TODO: líneas a los valores correctos +echo "DLR MATCOM COOL COMPILER V 0.1" +echo "Copyright (c) 2020: Leonel Alejandro García López, Jorge Daniel Valle Díaz, Roberto Marti Cedeño" # Llamar al compilador -echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +#echo "Compiling $INPUT_FILE into $OUTPUT_FILE" + +python3 main.py $INPUT_FILE $OUTPUT_FILE do_cil diff --git a/src/engine/__init__.py b/src/engine/__init__.py new file mode 100644 index 00000000..39c9033a --- /dev/null +++ b/src/engine/__init__.py @@ -0,0 +1,14 @@ +from .lexer import CoolLexer +from .parser import * +from .cp import evaluate_reverse_parse +from .cp.semantic import Scope +from .visitors import Builder +from .visitors import Checker +from .visitors import Collector +from .visitors import Format +from .visitors import Inferer +from .errors import * +from .codegen.to_cil import COOL_TO_CIL +from .codegen.cil_format import CIL_FORMATTER +from .codegen.to_mips import CIL_TO_MIPS +from .codegen.mips import * diff --git a/src/engine/codegen/__init__.py b/src/engine/codegen/__init__.py new file mode 100644 index 00000000..d5d01dd7 --- /dev/null +++ b/src/engine/codegen/__init__.py @@ -0,0 +1,3 @@ +from .cil_ast import * +from .cil import * +from .to_cil import * diff --git a/src/engine/codegen/cil.py b/src/engine/codegen/cil.py new file mode 100644 index 00000000..9ec3e012 --- /dev/null +++ b/src/engine/codegen/cil.py @@ -0,0 +1,302 @@ +from .cil_ast import * +from ..cp.semantic import VariableInfo, Scope + + +class BASE_COOL_CIL_TRANSFORM: + def __init__(self, context): + self.dottypes = [] + self.dotdata = [] + self.dotcode = [] + self.current_type = None + self.current_method = None + self.current_function = None + self.context = context + self.attr_declarations = {} + self._label_counter = 0 + self.define_object_type() + self.define_string_type() + self.define_io_type() + self.define_int_type() + self.define_bool_type() + + def label_counter_gen(self): + self._label_counter += 1 + return self._label_counter + + @property + def params(self): + return self.current_function.params + + @property + def localvars(self): + return self.current_function.localvars + + @property + def instructions(self): + return self.current_function.instructions + + def register_param(self, vinfo): + param_node = ParamNode(vinfo.name) + self.params.append(param_node) + return vinfo.name + + def register_local(self, vinfo): + name = f'local_{self.current_function.name[9:]}_{vinfo.name}_{len(self.localvars)}' + local_node = LocalNode(name) + self.localvars.append(local_node) + return name + + def define_internal_local(self): + vinfo = VariableInfo('internal', None) + return self.register_local(vinfo) + + def register_instruction(self, instruction): + self.instructions.append(instruction) + return instruction + + def to_function_name(self, method_name, type_name): + return f'function_{method_name}_at_{type_name}' + + def register_function(self, function_name): + function_node = FunctionNode(function_name, [], [], []) + self.dotcode.append(function_node) + return function_node + + def register_type(self, name): + type_node = TypeNode(name) + self.dottypes.append(type_node) + return type_node + + def register_data(self, value): + for data in self.dotdata: + if value == data.value: + return data + vname = f'data_{len(self.dotdata)}' + data_node = DataNode(vname, value) + self.dotdata.append(data_node) + return data_node + + def sort_case_list(self, case_expressions): + return sorted( + case_expressions, reverse=True, + key=lambda x: self.context.inheritance_deep(x.type.lex) + ) + ################################### + + def define_int_type(self): + self.current_type = self.context.get_type('Int') + type_node = self.register_type('Int') + type_node.attributes = [(attr.name) + for attr in self.current_type.all_attributes()] + type_node.attributes.append('value') + type_node.methods = [(method.name, self.to_function_name( + method.name, xtype.name)) for method, xtype in self.current_type.all_methods()] + + def define_bool_type(self): + self.current_type = self.context.get_type('Bool') + type_node = self.register_type('Bool') + type_node.attributes = [(attr.name) + for attr in self.current_type.all_attributes()] + type_node.attributes.append('value') + type_node.methods = [(method.name, self.to_function_name( + method.name, xtype.name)) for method, xtype in self.current_type.all_methods()] + + def define_string_type(self): + self.current_type = self.context.get_type('String') + type_node = self.register_type('String') + type_node.attributes = [(attr.name) + for attr in self.current_type.all_attributes()] + type_node.attributes.append('value') + type_node.methods = [(method.name, self.to_function_name( + method.name, xtype.name)) for method, xtype in self.current_type.all_methods()] + type_node.features = type_node.attributes + type_node.methods + + self.current_method = self.current_type.get_method('length') + type_name = self.current_type.name + self.current_function = self.register_function( + self.to_function_name(self.current_method.name, type_name)) + self_param = self.register_param(VariableInfo('self', None)) + dest = self.define_internal_local() + real_value = self.define_internal_local() + self.register_instruction(GetAttribNode( + real_value, self_param, 'value', 'String')) + self.register_instruction(LengthNode(dest, real_value)) + self.register_instruction(ReturnNode(dest)) + self.current_method = self.current_function = None + + self.current_method = self.current_type.get_method('concat') + type_name = self.current_type.name + self.current_function = self.register_function( + self.to_function_name(self.current_method.name, type_name)) + self_param = self.register_param(VariableInfo('self', None)) + str_param = self.register_param(VariableInfo('string', None)) + dest = self.define_internal_local() + real_value = self.define_internal_local() + self.register_instruction(GetAttribNode( + real_value, self_param, 'value', 'String')) + self.register_instruction(ConcatNode(dest, real_value, str_param)) + self.register_instruction(ReturnNode(dest)) + self.current_method = self.current_function = None + + self.current_method = self.current_type.get_method('substr') + type_name = self.current_type.name + self.current_function = self.register_function( + self.to_function_name(self.current_method.name, type_name)) + self_param = self.register_param(VariableInfo('self', None)) + real_value = self.define_internal_local() + self.register_instruction(GetAttribNode( + real_value, self_param, 'value', 'String')) + start = self.register_param(VariableInfo('start', None)) + length = self.register_param(VariableInfo('length', None)) + result = self.define_internal_local() + # sum_var = self.define_internal_local() + cmp_var1 = self.define_internal_local() + cmp_var2 = self.define_internal_local() + # cmp_var3 = self.define_internal_local() + local_error1 = self.define_internal_local() + local_error2 = self.define_internal_local() + # local_error3 = self.define_internal_local() + + no_error_label1 = LabelNode("error1") + no_error_label2 = LabelNode("error2") + # no_error_label3 = LabelNode("error3") + + zero = self.define_internal_local() + self.register_instruction(BoxNode(zero, 0)) + + length_var = self.define_internal_local() + self.register_instruction(LengthNode(length_var, real_value)) + + eol = self.register_data('\\n') + msg_eol = self.define_internal_local() + self.register_instruction(LoadNode(msg_eol, eol.name)) + + self.register_instruction(LessEqNode(cmp_var1, zero, start)) + self.register_instruction(IfGotoNode(cmp_var1, no_error_label1.label)) + error_msg = self.register_data("Invalid substring start") + self.register_instruction(LoadNode(local_error1, error_msg.name)) + self.register_instruction(ConcatNode( + local_error1, local_error1, msg_eol)) + self.register_instruction(PrintStrNode(local_error1)) + self.register_instruction(ErrorNode()) + self.register_instruction(no_error_label1) + + self.register_instruction(LessEqNode(cmp_var2, zero, length)) + self.register_instruction(IfGotoNode(cmp_var2, no_error_label2.label)) + error_msg = self.register_data("Invalid substring length") + self.register_instruction(LoadNode(local_error2, error_msg.name)) + self.register_instruction(ConcatNode( + local_error2, local_error2, msg_eol)) + self.register_instruction(PrintStrNode(local_error2)) + self.register_instruction(ErrorNode()) + self.register_instruction(no_error_label2) + + self.register_instruction(SubstringNode( + result, real_value, start, length)) + + self.register_instruction(ReturnNode(result)) + self.current_method = self.current_function = None + + self.current_type = None + + def define_io_type(self): + self.current_type = self.context.get_type('IO') + type_node = self.register_type('IO') + type_node.attributes = [(attr.name) + for attr in self.current_type.all_attributes()] + type_node.methods = [(method.name, self.to_function_name( + method.name, xtype.name)) for method, xtype in self.current_type.all_methods()] + type_node.features = type_node.attributes + type_node.methods + + self.current_method = self.current_type.get_method('out_string') + type_name = self.current_type.name + self.current_function = self.register_function( + self.to_function_name(self.current_method.name, type_name)) + self_local = self.register_param(VariableInfo("self", None)) + str_val = self.register_param(VariableInfo('str_val', None)) + self.register_instruction(PrintStrNode(str_val)) + self.register_instruction(ReturnNode(self_local)) + self.current_method = self.current_function = None + + self.current_method = self.current_type.get_method('in_string') + type_name = self.current_type.name + self.current_function = self.register_function( + self.to_function_name(self.current_method.name, type_name)) + dest = self.define_internal_local() + self.register_instruction(ReadStrNode(dest)) + self.register_instruction(ReturnNode(dest)) + self.current_method = self.current_function = None + + self.current_method = self.current_type.get_method('out_int') + type_name = self.current_type.name + self.current_function = self.register_function( + self.to_function_name(self.current_method.name, type_name)) + self_local = self.register_param(VariableInfo("self", None)) + int_val = self.register_param(VariableInfo('int_val', None)) + self.register_instruction(PrintIntNode(int_val)) + self.register_instruction(ReturnNode(self_local)) + self.current_method = self.current_function = None + + self.current_method = self.current_type.get_method('in_int') + type_name = self.current_type.name + self.current_function = self.register_function( + self.to_function_name(self.current_method.name, type_name)) + dest = self.define_internal_local() + self.register_instruction(ReadIntNode(dest)) + self.register_instruction(ReturnNode(dest)) + self.current_method = self.current_function = None + self.current_type = None + + def define_object_type(self): + self.current_type = self.context.get_type('Object') + type_node = self.register_type('Object') + type_node.attributes = [(attr.name) + for attr in self.current_type.all_attributes()] + type_node.methods = [(method.name, self.to_function_name( + method.name, xtype.name)) for method, xtype in self.current_type.all_methods()] + type_node.features = type_node.attributes + type_node.methods + + self.current_method = self.current_type.get_method('abort') + type_name = self.current_type.name + self.current_function = self.register_function( + self.to_function_name(self.current_method.name, type_name)) + self_local = self.register_param(VariableInfo('self', None)) + type_name = self.define_internal_local() + full_msg = self.define_internal_local() + + abort = self.register_data("Abort called from class ") + eol = self.register_data('\\n') + + abort_msg = self.define_internal_local() + self.register_instruction(LoadNode(abort_msg, abort.name)) + + msg_eol = self.define_internal_local() + self.register_instruction(LoadNode(msg_eol, eol.name)) + + self.register_instruction(TypeNameNode(type_name, self_local)) + self.register_instruction(ConcatNode(full_msg, abort_msg, type_name)) + self.register_instruction(ConcatNode(full_msg, full_msg, msg_eol)) + self.register_instruction(PrintStrNode(full_msg)) + self.register_instruction(AbortNode()) + self.current_method = self.current_function = None + + self.current_method = self.current_type.get_method('copy') + type_name = self.current_type.name + self.current_function = self.register_function( + self.to_function_name(self.current_method.name, type_name)) + self_local = self.register_param(VariableInfo('self', None)) + copy_inst = self.define_internal_local() + self.register_instruction(CopyNode(copy_inst, self_local)) + self.register_instruction(ReturnNode(copy_inst)) + self.current_method = self.current_function = None + + self.current_method = self.current_type.get_method('type_name') + type_name = self.current_type.name + self.current_function = self.register_function( + self.to_function_name(self.current_method.name, type_name)) + self_local = self.register_param(VariableInfo('self', None)) + type_name_inst = self.define_internal_local() + self.register_instruction(TypeNameNode(type_name_inst, self_local)) + self.register_instruction(ReturnNode(type_name_inst)) + self.current_method = self.current_function = None + self.current_type = None diff --git a/src/engine/codegen/cil_ast.py b/src/engine/codegen/cil_ast.py new file mode 100644 index 00000000..fbd12051 --- /dev/null +++ b/src/engine/codegen/cil_ast.py @@ -0,0 +1,294 @@ + + +class Node: + pass + + +class ProgramNode(Node): + def __init__(self, dottypes, dotdata, dotcode): + self.dottypes = dottypes + self.dotdata = dotdata + self.dotcode = dotcode + + +class TypeNode(Node): + def __init__(self, name): + self.name = name + self.name_dir = "" + self.attributes = [] + self.methods = [] + self.features = [] + + def __str__(self): + string_base = self.name + "\n" + + string_base += "Attrs \n" + + for attr in self.attributes: + string_base += str(attr) + "\n" + + string_base += "Methods \n" + + for methos in self.methods: + string_base += str(methos) + "\n" + + return string_base + + +class DataNode(Node): + def __init__(self, vname, value): + self.name = vname + self.value = value + + +class FunctionNode(Node): + def __init__(self, fname, params, localvars, instructions): + self.name = fname + self.params = params + self.localvars = localvars + self.instructions = instructions + + +class ParamNode(Node): + def __init__(self, name): + self.name = name + + +class LocalNode(Node): + def __init__(self, name): + self.name = name + + def __str__(self): + return self.name + + def __repr__(self): + return str(self) + + +class InstructionNode(Node): + pass + + +class GetAttribNode(InstructionNode): + def __init__(self, dest, obj, attrib, typex): + self.dest = dest + self.obj = obj + self.attrib = attrib + self.type = typex + + +class ConformsNode(InstructionNode): + def __init__(self, dest, expr, typex): + self.dest = dest + self.expr = expr # variable id + self.type = typex + + +class SetAttribNode(InstructionNode): + def __init__(self, obj, attrib, value, typex): + self.obj = obj + self.attrib = attrib + self.value = value + self.type = typex + + +class AssignNode(InstructionNode): + def __init__(self, dest, source): + self.dest = dest + self.source = source + + +class EmptyArgs(InstructionNode): + def __init__(self, args): + self.args = args + + +class ArithmeticNode(InstructionNode): + def __init__(self, dest, left, right): + self.dest = dest + self.left = left + self.right = right + + +class UnaryNode(InstructionNode): + def __init__(self, dest, expression): + self.dest = dest + self.expression = expression + + +class ComplementNode(UnaryNode): + pass + + +class IsVoidNode(UnaryNode): + pass + + +class NotNode(UnaryNode): + pass + + +class PlusNode(ArithmeticNode): + pass + + +class MinusNode(ArithmeticNode): + pass + + +class StarNode(ArithmeticNode): + pass + + +class DivNode(ArithmeticNode): + pass + + +class EqualNode(ArithmeticNode): + pass + + +class LessNode(ArithmeticNode): + pass + + +class LessEqNode(ArithmeticNode): + pass + + +class BoxNode(InstructionNode): + def __init__(self, dest, value): + self.dest = dest + self.value = value + + +class AbortNode(InstructionNode): + pass + + +class AllocateNode(InstructionNode): + def __init__(self, dest, itype): + self.dest = dest + self.type = itype + + +class TypeOfNode(InstructionNode): + def __init__(self, obj, dest): + self.obj = obj + self.dest = dest + + +class LabelNode(InstructionNode): + def __init__(self, label): + self.label = label + + +class GotoNode(InstructionNode): + def __init__(self, label): + self.label = label + + +class IfGotoNode(InstructionNode): + def __init__(self, value, label): + self.value = value + self.label = label + + +class StaticCallNode(InstructionNode): + def __init__(self, function, dest): + self.dest = dest + self.function = function + + +class DynamicCallNode(InstructionNode): + def __init__(self, obj, xtype, method, dest): + self.obj = obj + self.type = xtype + self.method = method + self.dest = dest + + +class ArgNode(InstructionNode): + def __init__(self, name): + self.name = name + + +class ErrorNode(InstructionNode): + def __init__(self, error=0): + self.error = error + + +class CopyNode(InstructionNode): + def __init__(self, dest, obj): + self.dest = dest + self.obj = obj + + +class TypeNameNode(InstructionNode): + def __init__(self, dest, typex): + self.dest = dest + self.type = typex + + +class ReturnNode(InstructionNode): + def __init__(self, value=None): + self.value = value + + +class LoadNode(InstructionNode): + def __init__(self, dest, msg): + self.dest = dest + self.msg = msg + + +class LengthNode(InstructionNode): + def __init__(self, dest, msg): + self.dest = dest + self.msg = msg + + +class ConcatNode(InstructionNode): + def __init__(self, dest, msg1, msg2): + self.dest = dest + self.msg1 = msg1 + self.msg2 = msg2 + + +class StringEqualNode(InstructionNode): + def __init__(self, dest, msg1, msg2): + self.dest = dest + self.msg1 = msg1 + self.msg2 = msg2 + + +class SubstringNode(InstructionNode): + def __init__(self, dest, msg1, start, length): + self.dest = dest + self.msg1 = msg1 + self.start = start + self.length = length + + +class PrintStrNode(InstructionNode): + def __init__(self, str_addr): + self.str_addr = str_addr + + +class PrintIntNode(InstructionNode): + def __init__(self, str_addr): + self.str_addr = str_addr + + +class ReadIntNode(InstructionNode): + def __init__(self, dest): + self.dest = dest + + +class ReadStrNode(InstructionNode): + def __init__(self, dest): + self.dest = dest + + +class VoidNode(InstructionNode): + def __init__(self, dest): + self.dest = dest diff --git a/src/engine/codegen/cil_format.py b/src/engine/codegen/cil_format.py new file mode 100644 index 00000000..a9d4f139 --- /dev/null +++ b/src/engine/codegen/cil_format.py @@ -0,0 +1,200 @@ +from .cil_ast import * + +from ..cp import visitor + + +class CIL_FORMATTER(object): + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node: ProgramNode): + dottypes = '\n'.join(self.visit(t) for t in node.dottypes) + dotdata = '\n'.join(self.visit(t) for t in node.dotdata) + dotcode = '\n'.join(self.visit(t) for t in node.dotcode) + + return f'.TYPES\n{dottypes}\n\n.DATA\n{dotdata}\n\n.CODE\n{dotcode}' + + @visitor.when(DataNode) + def visit(self, node: DataNode): + return f'{node.name} = "{node.value}"' + + @visitor.when(TypeNode) + def visit(self, node: TypeNode): + attributes = '\n\t'.join(f'attribute {x}' for x in node.attributes) + methods = '\n\t'.join(f'method {x}: {y}' for x, y in node.methods) + + return f'type {node.name} {{\n\t{attributes}\n\n\t{methods}\n}}' + + @visitor.when(FunctionNode) + def visit(self, node: FunctionNode): + params = '\n\t'.join(self.visit(x) for x in node.params) + localvars = '\n\t'.join(self.visit(x) for x in node.localvars) + instructions = '\n\t'.join(self.visit(x) for x in node.instructions) + + return f'function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}' + + @visitor.when(ParamNode) + def visit(self, node: ParamNode): + return f'PARAM {node.name}' + + @visitor.when(LocalNode) + def visit(self, node: LocalNode): + return f'LOCAL {node.name}' + + @visitor.when(AssignNode) + def visit(self, node: AssignNode): + return f'{node.dest} = {node.source}' + + @visitor.when(PlusNode) + def visit(self, node: PlusNode): + return f'{node.dest} = {node.left} + {node.right}' + + @visitor.when(MinusNode) + def visit(self, node: MinusNode): + return f'{node.dest} = {node.left} - {node.right}' + + @visitor.when(StarNode) + def visit(self, node: StarNode): + return f'{node.dest} = {node.left} * {node.right}' + + @visitor.when(DivNode) + def visit(self, node: DivNode): + return f'{node.dest} = {node.left} / {node.right}' + + @visitor.when(AllocateNode) + def visit(self, node: AllocateNode): + return f'{node.dest} = ALLOCATE {node.type}' + + @visitor.when(TypeOfNode) + def visit(self, node: TypeOfNode): + return f'{node.dest} = TYPEOF {node.obj}' + + @visitor.when(StaticCallNode) + def visit(self, node: StaticCallNode): + return f'{node.dest} = CALL {node.function}' + + @visitor.when(DynamicCallNode) + def visit(self, node: DynamicCallNode): + return f'{node.dest} = VCALL {node.type} {node.method}' + + @visitor.when(ArgNode) + def visit(self, node: ArgNode): + return f'ARG {node.name}' + + @visitor.when(ReturnNode) + def visit(self, node: ReturnNode): + return f'RETURN {node.value if node.value is not None else ""}' + + @visitor.when(ReadStrNode) + def visit(self, node: ReadStrNode): + return f'{node.dest} = READSTR' + + @visitor.when(PrintStrNode) + def visit(self, node: PrintStrNode): + return f'PRINTSTR {node.str_addr}' + + @visitor.when(LoadNode) + def visit(self, node: LoadNode): + return f'{node.dest} = LOAD {node.msg}' + + @visitor.when(LengthNode) + def visit(self, node: LengthNode): + return f'{node.dest} = LENGTH {node.msg}' + + @visitor.when(ConcatNode) + def visit(self, node: ConcatNode): + return f'{node.dest} = CONCAT {node.msg1} {node.msg2}' + + @visitor.when(EmptyArgs) + def visit(self, node: EmptyArgs): + return f'CLEAR {node.args} ARGS' + + @visitor.when(SubstringNode) + def visit(self, node: SubstringNode): + return f'{node.dest} = SUBSTRING {node.msg1} {node.start} {node.length}' + + @visitor.when(ReadIntNode) + def visit(self, node: ReadIntNode): + return f'{node.dest} = READINT' + + @visitor.when(PrintIntNode) + def visit(self, node: PrintIntNode): + return f'PRINTINT {node.str_addr}' + + @visitor.when(GetAttribNode) + def visit(self, node: GetAttribNode): + return f'{node.dest} = GETATTR {node.obj} {node.attrib}' + + @visitor.when(SetAttribNode) + def visit(self, node: SetAttribNode): + return f'SETATTR {node.attrib} OF {node.obj}_{node.type} = {node.value}' + + @visitor.when(LabelNode) + def visit(self, node: LabelNode): + return f'LABEL {node.label}' + + @visitor.when(GotoNode) + def visit(self, node: GotoNode): + return f'GOTO {node.label}' + + @visitor.when(IfGotoNode) + def visit(self, node: IfGotoNode): + return f'IF {node.value} GOTO {node.label}' + + @visitor.when(ComplementNode) + def visit(self, node: ComplementNode): + return f'{node.dest} = COMPLEMENT {node.expression}' + + @visitor.when(LessNode) + def visit(self, node: LessNode): + return f'{node.dest} = {node.left} < {node.right}' + + @visitor.when(IsVoidNode) + def visit(self, node: IsVoidNode): + return f'{node.dest} = ISVOID {node.expression}' + + @visitor.when(LessEqNode) + def visit(self, node: LessEqNode): + return f'{node.dest} = {node.left} <= {node.right}' + + @visitor.when(EqualNode) + def visit(self, node: EqualNode): + return f'{node.dest} = {node.left} == {node.right}' + + @visitor.when(ErrorNode) + def visit(self, node: ErrorNode): + return f'ERROR {node.error}' + + @visitor.when(BoxNode) + def visit(self, node: BoxNode): + return f'{node.dest} = {node.value}' + + @visitor.when(AbortNode) + def visit(self, node: AbortNode): + return f'ABORT' + + @visitor.when(VoidNode) + def visit(self, node: VoidNode): + return f'{node.dest} = VOID' + + @visitor.when(ConformsNode) + def visit(self, node: ConformsNode): + return f'{node.dest} = COMFORM {node.expr} {node.type}' + + @visitor.when(NotNode) + def visit(self, node: NotNode): + return f'{node.dest} = NOT {node.expression}' + + @visitor.when(StringEqualNode) + def visit(self, node: StringEqualNode): + return f'{node.dest} = STREQ {node.msg1} {node.msg2}' + + @visitor.when(CopyNode) + def visit(self, node: CopyNode): + return f'{node.dest} = COPY {node.obj}' + + @visitor.when(TypeNameNode) + def visit(self, node: TypeNameNode): + return f'{node.dest} = TYPENAME {node.type}' diff --git a/src/engine/codegen/mips.py b/src/engine/codegen/mips.py new file mode 100644 index 00000000..beec9256 --- /dev/null +++ b/src/engine/codegen/mips.py @@ -0,0 +1,552 @@ +from enum import Enum +from typing import Dict, List +from .cil_ast import TypeNode + +word_size = 4 + +string_max_size = 1000 + + +class GlobalDescriptor: + + def __init__(self, dottypes: List[TypeNode], name_ptrs): + self.vTable = None + self.Types = {} + + methods = {} + + index = 0 + + start_method = 0 + end_method = 0 + + for dottype in dottypes: + + methds = [] + + for (method_name, method_tag) in dottype.methods: + name = dottype.name + "_" + method_name + methods[name] = method_tag + methds.append(method_name) + end_method += 1 + + self.Types[dottype.name] = MemoryType( + dottype.name, index, dottype.attributes, methds, start_method, name_ptrs[dottype.name]) + + start_method = end_method + index += 1 + + self.vTable = VTable(methods) + + def __getitem__(self, id): + for mem in self.Types.values(): + if mem.id == id: + return mem + + raise Exception(f"Class {id} not present") + + +class VTable: + + def __init__(self, methods): + self.methods = methods + + def size(self): + return len(self.methods) + + def __getitem__(self, name): + return self.methods[name] + + def get_index(self, name): + return list(self.methods.keys()).index(name) + + @staticmethod + def build_name(name, _type): + return f"{_type}_{name}" + + +class MemoryType: + + def __init__(self, name, _id, attrs, methods, base_index, ptr_name): + self.name = name + self.id = _id + self.attrs = attrs + self.methods = methods + self.vtable = base_index + self.ptr_name = ptr_name + + def size(self): + return 4 + len(self.attrs) + + def get_attr_index(self, attr): + return 4 + self.attrs.index(attr) + + def get_method_index(self, method): + return self.methods.index(method) + + def get_ptr_name(self): + return self.ptr_name + + +class Registers: + zero = '$zero' # Constant 0 + at = '$at' # Reserved for assembler + v0 = '$v0' # Expression evaluation and + v1 = '$v1' # results of a function + a0 = '$a0' # Argument 1 + a1 = '$a1' # Argument 2 + a2 = '$a2' # Argument 3 + a3 = '$a3' # Argument 4 + t0 = '$t0' # Temporary(not preserved across call) + t1 = '$t1' # Temporary(not preserved across call) + t2 = '$t2' # Temporary(not preserved across call) + t3 = '$t3' # Temporary(not preserved across call) + t4 = '$t4' # Temporary(not preserved across call) + t5 = '$t5' # Temporary(not preserved across call) + t6 = '$t6' # Temporary(not preserved across call) + t7 = '$t7' # Temporary(not preserved across call) + s0 = '$s0' # Saved temporary(preserved across call) + s1 = '$s1' # Saved temporary(preserved across call) + s2 = '$s2' # Saved temporary(preserved across call) + s3 = '$s3' # Saved temporary(preserved across call) + s4 = '$s4' # Saved temporary(preserved across call) + s5 = '$s5' # Saved temporary(preserved across call) + s6 = '$s6' # Saved temporary(preserved across call) + s7 = '$s7' # Saved temporary(preserved across call) + t8 = '$t8' # Temporary(not preserved across call) + t9 = '$t9' # Temporary(not preserved across call) + k0 = '$k0' # Reserved for OS kernel + k1 = '$k1' # Reserved for OS kernel + gp = '$gp' # Pointer to global area + sp = '$sp' # Stack pointer + fp = '$fp' # Frame pointer + ra = '$ra' # Return address(used by function call) + + +# class TypeData: + # def __init__(self, type_number: int, typex: TypeNode): + # self.pos = type_number + # self.type = typex + # self.str: str = typex.name_dir + # self.attr_offsets: Dict[str, int] = dict() + # self.func_offsets: Dict[str, int] = dict() + # self.func_names: Dict[str, str] = dict() + # self.set_type() + + # def set_type(self): + # for idx, feature in enumerate(self.type.features): + # if isinstance(feature, str): + # self.attr_offsets[feature] = idx + 2 + # else: + # func_name, long_name = feature + # self.func_offsets[func_name] = idx + 2 + # self.func_names[func_name] = long_name + + +class MipsLabel(str, Enum): + + word = ".word" + half = ".half" + byte = ".byte" + ascii_ = ".ascii" + asciiz = ".asciiz" + space = ".space" + aling = ".align" + text = ".text" + data = ".data" + + +reg = Registers + + +class MipsCode: + def __init__(self): + self.dotdata = [] + self.dotcode = [] + + # Meta Functions + + def compile(self): + return '\n'.join([MipsLabel.data] + self.dotdata + [] + [MipsLabel.text] + self.dotcode) + + def _write(self, line): + self.dotcode.append(line) + + def _write_data(self, line): + self.dotdata.append(line) + + def data_label(self, lname): + self._write_data(f'{lname}:') + + def empty_line(self): + self._write('') + + def offset(self, r, offset: int = 0): + return f"{offset}({r})" + + def asciiz(self, string): + self._write_data(f'.asciiz "{string}"') + + def push(self, register): + self.addi(reg.sp, reg.sp, -4) + self.store_memory(register, self.offset(reg.sp)) + + def pop(self, register): + self.load_memory(register, self.offset(reg.sp)) + self.addi(reg.sp, reg.sp, 4) + + def load_memory(self, dst, address: str): + self.lw(dst, address) + # self.sll(reg.t8, reg.t8, 16) + # self.la(reg.t7, address) + # self.addi(reg.t7, reg.t7, 4) + # self.lw(reg.t9, self.offset(reg.t7)) + # self.or_(dst, reg.t8, reg.t9) + + def store_memory(self, src: Registers, address: str): + self.sw(src, address) + # self.la(reg.t8, address) + + # self.srl(reg.t9, src, 16) + + # self.sw(reg.t9, self.offset(reg.t8)) # store high bits + # self.sw(src, self.offset(reg.t8, 4)) # store low bits + + # System Calls + + def syscall(self, code: int): + self.li(reg.v0, code) + self._write('syscall') + + def comment(self, text: str): + self._write(f"# {text}") + + def label(self, name: str): + self._write(f"{name}:") + + def print_str(self, _str): + return self.syscall(4) + + def print_int(self, _int): + return self.syscall(1) + + def read_int(self): + return self.syscall(5) + + def read_string(self): + return self.syscall(8) + + def sbrk(self): + return self.syscall(9) + + def exit(self): + return self.syscall(10) + + # Arithmetic and Logical Operations + def abs(self, rdest, rsrc): + ''' + Absolute Value + ''' + self._write(f'abs {rdest}, {rsrc}') + + def addiu(self, rdest, rsrc, constant): + ''' + Addition Immediate (without overflow) + ''' + self._write(f'addiu {rdest}, {rsrc}, {constant}') + + def addi(self, rdest, rsrc, constant): + ''' + Addition Immediate (with overflow) + ''' + self._write(f'addi {rdest}, {rsrc}, {constant}') + + def add(self, rdest, rsrc, src): + ''' + + Addition (with overflow) + ''' + self._write(f'add {rdest}, {rsrc}, {src}') + + def addu(self, rdest, rsrc, src): + ''' + Addition (without overflow) + ''' + self._write(f'addu {rdest}, {rsrc}, {src}') + + def and_(self, rdest, rsrc1, rsrc2): + ''' + AND + ''' + self._write(f'and {rdest}, {rsrc1}, {rsrc2}') + + def andi(self, rdest, rsrc, constant): + ''' + ANDI Inmediate + ''' + self._write(f'andi {rdest}, {rsrc}, {constant}') + + def div(self, rdest_src, rsrc1, rsrc2=None): + ''' + Divide (signed) + ''' + if rsrc2 is None: + self._write(f'div {rdest_src}, {rsrc1}') + else: + self._write(f'div {rdest_src}, {rsrc1}, {rsrc2}') + + def divu(self, rdest_src, rsrc1, rsrc2=None): + ''' + Divide (unsigned) + ''' + if rsrc2 is None: + self._write(f'divu {rdest_src}, {rsrc1}') + else: + self._write(f'divu {rdest_src}, {rsrc1}, {rsrc2}') + + def mult(self, rdest, rsrc1): + ''' + Multiply + ''' + self._write(f'mult {rdest}, {rsrc1}') + + def neg(self, rdest, rsrc): + ''' + Negate Value (with overflow) + ''' + self._write(f'neg {rdest}, {rsrc}') + + def negu(self, rdest, rsrc): + ''' + Negate Value (without overflow) + ''' + self._write(f'negu {rdest}, {rsrc}') + + def not_(self, rdest, rsrc): + ''' + Not + ''' + self._write(f'or {rdest}, {rsrc}') + + def or_(self, rdest, rsrc1, src2): + ''' + Or + ''' + self._write(f'or {rdest}, {rsrc1}, {src2}') + + def nor(self, rdest, rsrc1, src2): + ''' + Nor + ''' + self._write(f'nor {rdest}, {rsrc1}, {src2}') + + def ori(self, rdest, rsrc1, constant): + ''' + Or Immediate + ''' + self._write(f'ori {rdest}, {rsrc1}, {constant}') + + def rem(self, rdest, rsrc1, src2): + ''' + Remainder + ''' + self._write(f'rem {rdest}, {rsrc1}, {src2}') + + def remu(self, rdest, rsrc1, src2): + ''' + Unsigned Remainder + ''' + self._write(f'remu {rdest}, {rsrc1}, {src2}') + + def sub(self, rdest, rsrc1, src2): + ''' + Substract (with overflow) + ''' + self._write(f'sub {rdest}, {rsrc1}, {src2}') + + def subu(self, rdest, rsrc1, src2): + ''' + Substract (without overflow) + ''' + self._write(f'subu {rdest}, {rsrc1}, {src2}') + + def sll(self, dst, rl, value: int): + ''' + Shift Left Logical + ''' + self._write(f"sll {dst}, {rl}, {value}") + + # Constant Manipulating + def li(self, rdest, constant): + ''' + Load Immediate + ''' + self._write(f'li {rdest}, {int(constant)}') + + # Comparison Instructions + def seq(self, rdest, rsrc1, src2): + ''' + Set Equal + ''' + self._write(f'seq {rdest}, {rsrc1}, {src2}') + + def sge(self, rdest, rsrc1, src2): + ''' + Set Greater Than Equal er Than Equal Unsigned + ''' + self._write(f'sge {rdest}, {rsrc1}, {src2}') + + def sle(self, rdest, rsrc1, src2): + ''' + Set Less Than Equal Than Equal Unsigned + ''' + self._write(f'sle {rdest}, {rsrc1}, {src2}') + + def slt(self, rdest, rsrc1, src2): + ''' + Set Less Than + ''' + self._write(f'slt {rdest}, {rsrc1}, {src2}') + + def slti(self, rdest, rsrc1, value): + ''' + Set Less Than Immediate + ''' + self._write(f'slti {rdest}, {rsrc1}, {value}') + + def srl(self, rdest, rsrc1, src2): + ''' + Shift Right Logical + ''' + self._write(f'srl {rdest}, {rsrc1}, {src2}') + + # Branch and Jump + + def b(self, label): + ''' + Branch instruction + ''' + self._write(f'b {label}') + + def beq(self, rsrc1, src2, label): + ''' + Branch on Equal + ''' + self._write(f'beq {rsrc1}, {src2}, {label}') + + def beqz(self, rsrc1, label): + ''' + Branch on Equal Zero + ''' + self._write(f'beqz {rsrc1}, {label}') + + def bne(self, rsrc1, src2, label): + ''' + Branch on Not Equal + ''' + self._write(f'bne {rsrc1}, {src2}, {label}') + + def bnez(self, rsrc1, label): + ''' + Branch on Not Equal Zero + ''' + self._write(f'bnez {rsrc1}, {label}') + + def j(self, label): + ''' + Jump + ''' + self._write(f'j {label}') + + def jal(self, label): + ''' + Jump and Link + ''' + self._write(f'jal {label}') + + def jr(self, rsrc): + ''' + Jump Registers + ''' + self._write(f'jr {rsrc}') + + def jalr(self, rdest): + ''' + Jump and Link Register + ''' + self._write(f"jalr {rdest}") + # Load Instructions + + def la(self, rdest, address): + ''' + Load Address + ''' + self._write(f'la {rdest}, {address}') + + def lb(self, rdest, address): + ''' + Load Byte + ''' + self._write(f'lb {rdest}, {address}') + + def lw(self, reg, address): + ''' + Load Word + ''' + self._write(f'lw {reg}, {address}') + + def ld(self, rdest, address): + ''' + Load Double-Word + ''' + self._write(f'la {rdest}, {address}') + + # Store Instructions + def sb(self, rsrc, address): + ''' + Store Byte + ''' + self._write(f'sb {rsrc}, {address}') + + def sw(self, rsrc, address): + ''' + Store Word + ''' + self._write(f'sw {rsrc}, {address}') + + def sd(self, rsrc, address): + ''' + Store Double-Word + ''' + self._write(f'sd {rsrc}, {address}') + + # Data Movement Instructions + def move(self, rdest, rsrc): + ''' + Move + ''' + self._write(f'move {rdest}, {rsrc}') + + def mfhi(self, rdest): + ''' + Move from `high` + ''' + self._write(f'mfhi {rdest}') + + def mflo(self, rdest): + ''' + Move from `low` + ''' + self._write(f'mflo {rdest}') + + # VTble allocate + def allocate_vtable(self, size, _reg): + ''' + Allocate Vtable and store its adrress into reg + ''' + + self.comment("Allocate Vtable") + vtable_size = size * word_size + self.li(reg.a0, vtable_size) + self.sbrk() + self.move(_reg, reg.v0) diff --git a/src/engine/codegen/to_cil.py b/src/engine/codegen/to_cil.py new file mode 100644 index 00000000..5f77c6cb --- /dev/null +++ b/src/engine/codegen/to_cil.py @@ -0,0 +1,533 @@ +from typing import List +from engine import parser as cool +from engine.cp.semantic import Context +from .cil_ast import * +from ..cp import visitor +from ..cp.semantic import VariableInfo, Scope +from .cil import BASE_COOL_CIL_TRANSFORM + + +class COOL_TO_CIL(BASE_COOL_CIL_TRANSFORM): + + def define_binary_node(self, node: cool.BinaryNode, scope, cil_node: Node): + result = self.define_internal_local() + left = self.visit(node.left, scope) + right = self.visit(node.right, scope) + self.register_instruction(cil_node(result, left, right)) + return result + + def define_unary_node(self, node: cool.UnaryNode, scope, cil_node: Node): + result = self.define_internal_local() + expr = self.visit(node.expression, scope) + self.register_instruction(cil_node(result, expr)) + return result + + def get_children_types_inheritance(self, type_names: List[str]): + for_visit = set(type_names) + types = set(type_names) + while len(for_visit): + for_visit_child = set() + for typex in for_visit: + children = [] + for child, parent in self.context.inheritance.items(): + if parent == typex: + children.append(child) + for_visit_child.add(child) + types.add(child) + + for_visit = for_visit_child + + # print(type_names) + # print(types) + + return types + + def extend_case_list(self, case_expressions: List[cool.CaseActionExpression]): + cases_by_type = { + case.type.lex: case + for case in case_expressions + } + types = self.get_children_types_inheritance( + type_names=list(cases_by_type.keys()) + ) + types = sorted( + types, + key=lambda t: self.context.inheritance_deep(t), + reverse=True + ) + ordered_cases = [] + for typex in [self.context.get_type(t) for t in types]: + temp = typex + while True: + if temp.name in cases_by_type: + case = cases_by_type[temp.name] + new_case = cool.CaseActionExpression( + case.id, + typex.name, + case.expression, + ) + ordered_cases.append(new_case) + break + temp = self.context.get_type( + self.context.inheritance[temp.name]) # get_parent + return ordered_cases + + def sort_class_declar(self, program: cool.ProgramNode): + self.context: Context + program.declarations = sorted( + ( + declaration + for declaration in program.declarations + if isinstance(declaration, cool.ClassDeclarationNode) + ), + # reverse=True, + key=lambda cd: self.context.inheritance_deep(cd.id.lex), + ) + + def save_attr_initializations(self, node: cool.ProgramNode, scope): + self.attr_declarations = dict() + self.attr_declarations['Object'] = [] + self.attr_declarations['IO'] = [] + self.attr_declarations['Int'] = [ + cool.AttrDeclarationNode("value", 'Int') + ] + self.attr_declarations['String'] = [ + cool.AttrDeclarationNode("value", 'String') + ] + self.attr_declarations['Bool'] = [ + cool.AttrDeclarationNode("value", 'Bool') + ] + + for built_in in ['IO', 'Int', 'String', 'Bool', 'Object']: + self.create_constructor(self.attr_declarations[built_in], built_in) + + for declaration in node.declarations: + self.attr_declarations[declaration.id.lex] = [] + if declaration.parent and not declaration.parent.lex in ['IO', 'Int', 'String', 'Bool', 'Object']: + self.attr_declarations[declaration.id.lex] += self.attr_declarations[declaration.parent.lex] + self.attr_declarations[declaration.id.lex] += [ + feature for feature in declaration.features + if isinstance(feature, cool.AttrDeclarationNode) + ] + self.create_constructor( + self.attr_declarations[declaration.id.lex], declaration.id.lex + ) + + def create_constructor(self, attr_declarations: List[cool.AttrDeclarationNode], type_name): + self.current_function = self.register_function(f'ctor_{type_name}') + self.current_type = self.context.get_type(type_name) + instance = self.register_param(VariableInfo('self', self.current_type)) + + scope = Scope() + instance = scope.define_variable('self', self.current_type) + + self_instance_name = instance.name + for attr in attr_declarations: + result = None + if attr.expression: + result = self.visit(attr.expression, scope) + elif attr.type == 'String': + result = self.register_data("").name + else: + result = self.define_internal_local() + self.register_instruction(VoidNode(result)) + + self.register_instruction( + SetAttribNode(self_instance_name, attr.id.lex, result, type_name)) + + self.register_instruction(ReturnNode(self_instance_name)) + + self.current_type = None + self.current_function = None + + @visitor.on('node') + def visit(self, node, scope): + pass + + @visitor.when(cool.ProgramNode) + def visit(self, node: cool.ProgramNode, scope=None): + scope = Scope() + self.sort_class_declar(node) + self.save_attr_initializations(node, scope) + # entry + self.current_function = self.register_function('entry') + # call Constructor + instance = self.define_internal_local() + self.current_type = self.context.get_type('Main') + self.register_instruction( + AllocateNode(instance, self.current_type.name) + ) + self.register_instruction(ArgNode(instance)) + self.register_instruction( + StaticCallNode(f'ctor_{self.current_type.name}', instance)) + self.register_instruction(EmptyArgs(1)) + + # call Main.main + result = self.define_internal_local() + self.register_instruction(ArgNode(instance)) + name = self.to_function_name('main', 'Main') + self.register_instruction(StaticCallNode(name, result)) + self.register_instruction(EmptyArgs(1)) + self.current_function = None + + classes = [ + declaration + for declaration in node.declarations + if isinstance(declaration, cool.ClassDeclarationNode) + ] + for declaration in classes: + self.visit(declaration, scope.create_child()) + + return ProgramNode(self.dottypes, self.dotdata, self.dotcode) + + @visitor.when(cool.ClassDeclarationNode) + def visit(self, node: cool.ClassDeclarationNode, scope: Scope): + self.current_type = self.context.get_type(node.id.lex) + type_node = self.register_type(node.id.lex) + type_node.attributes = [(attr.name) + for attr in self.current_type.all_attributes()] + type_node.methods = [(method.name, self.to_function_name( + method.name, xtype.name)) for method, xtype in self.current_type.all_methods()] + type_node.features = type_node.attributes + type_node.methods + fun_declarations = (f for f in node.features if isinstance( + f, cool.FuncDeclarationNode)) + for feature in fun_declarations: + self.visit(feature, scope) + + self.current_type = None + + @visitor.when(cool.FuncDeclarationNode) + def visit(self, node: cool.FuncDeclarationNode, scope: Scope): + fun_scope = scope.create_child() + self.current_method = self.current_type.get_method(node.id.lex) + type_name = self.current_type.name + + self.current_function = self.register_function( + self.to_function_name(node.id.lex, type_name)) + self_local = self.register_param(VariableInfo('self', None)) + fun_scope.define_variable('self', self_local) + for param_name, param_type in node.params: + fun_scope.define_variable(param_name.lex, param_type.lex) + self.register_param(VariableInfo(param_name.lex, param_type.lex)) + + body = self.visit(node.body, fun_scope) + + self.register_instruction(ReturnNode(body)) + self.current_method = None + + @visitor.when(cool.AttrDeclarationNode) + def visit(self, node: cool.AttrDeclarationNode, scope: Scope, typex): + result = None + if node.expression: + result = self.visit(node.expression, scope) + elif node.type == 'String': + result = self.register_data("").name + else: + result = self.define_internal_local() + self.register_instruction(VoidNode(result)) + self_inst = scope.find_variable('self').name + self.register_instruction( + SetAttribNode(self_inst, node.id.lex, result, typex)) + + @visitor.when(cool.BlockNode) + def visit(self, node: cool.BlockNode, scope): + result = None + for expr in node.expressions: + result = self.visit(expr, scope) + # self.register_instruction(AssignNode(result, val)) + return result + + @visitor.when(cool.AssignNode) + def visit(self, node: cool.AssignNode, scope: Scope): + expr = self.visit(node.expression, scope) + var_info = scope.find_variable(node.id.lex) + if not var_info: + selfx = scope.find_variable('self').name + self.register_instruction(SetAttribNode( + selfx, node.id.lex, expr, self.current_type.name)) + else: + var_info = var_info.real_name + self.register_instruction(AssignNode(var_info, expr)) + return expr + + @visitor.when(cool.NewNode) + def visit(self, node: cool.NewNode, scope): + new_local = self.define_internal_local() + typex = self.context.get_type(node.type.lex) + self.register_instruction(AllocateNode(new_local, typex.name)) + self.register_instruction(ArgNode(new_local)) + self.register_instruction( + StaticCallNode(f'ctor_{typex.name}', new_local)) + self.register_instruction(EmptyArgs(1)) + return new_local + + @visitor.when(cool.IfThenElseNode) + def visit(self, node: cool.IfThenElseNode, scope): + label_counter = self.label_counter_gen() + cond = self.visit(node.condition, scope) + child_scope = scope.create_child() + true_label = LabelNode(f'TRUE_{label_counter}') + end_label = LabelNode(f'END_{label_counter}') + result = self.define_internal_local() + self.register_instruction(IfGotoNode( + cond, true_label.label)) + label_counter += 1 + false_expr = self.visit(node.else_body, child_scope) + self.register_instruction(AssignNode(result, false_expr)) + self.register_instruction( + GotoNode(end_label.label)) + self.register_instruction(true_label) + + true_expr = self.visit(node.if_body, child_scope) + self.register_instruction(AssignNode(result, true_expr)) + self.register_instruction(end_label) + label_counter = self.label_counter_gen() + + return result + + @visitor.when(cool.WhileLoopNode) + def visit(self, node: cool.WhileLoopNode, scope): + while_scope = scope.create_child() + label_counter = self.label_counter_gen() + start_label = LabelNode(f'START_{label_counter}') + continue_label = LabelNode(f'CONTINUE_{label_counter}') + end_label = LabelNode(f'END_{label_counter}') + + self.register_instruction(start_label) + + cond = self.visit(node.condition, scope) + self.register_instruction(IfGotoNode(cond, continue_label.label)) + self.register_instruction(GotoNode(end_label.label)) + self.register_instruction(continue_label) + self.visit(node.body, while_scope) + label_counter = self.label_counter_gen() + self.register_instruction(GotoNode(start_label.label)) + self.register_instruction(end_label) + + result = self.define_internal_local() + self.register_instruction(VoidNode(result)) + return result + + @visitor.when(cool.CaseOfNode) + def visit(self, node: cool.CaseOfNode, scope: Scope): + label_counter = self.label_counter_gen() + expr = self.visit(node.expression, scope) + result = self.define_internal_local() + end_label = LabelNode(f'END_{label_counter}') + error_label = LabelNode(f'ERROR_CASE_{label_counter}') + # TODO: Label error logic if is void + + case_expressions = self.extend_case_list(node.branches) + # print(case_expressions) + + for i, case in enumerate(case_expressions): + next_branch_label = LabelNode( + f'CASE_{case.id.lex}_{i}_{label_counter}' + ) + child_scope = scope.create_child() + expr_i = self.visit( + case, child_scope, + expr=expr, + next_label=next_branch_label, + label_id=label_counter + ) + self.register_instruction(AssignNode(result, expr_i)) + self.register_instruction(GotoNode(end_label.label)) + self.register_instruction(next_branch_label) + + self.register_instruction(error_label) + # TODO: specify the message error here [ i think :/ ] + self.register_instruction(ErrorNode()) + self.register_instruction(end_label) + + return result + + @visitor.when(cool.CaseActionExpression) + def visit(self, node: cool.CaseActionExpression, scope: Scope, expr=None, next_label=None, label_id=0): + test_res = self.define_internal_local() + + matching_label = LabelNode( + f'CASE_MATCH_{node.id.lex}_{node.type.lex}_{label_id}') + self.register_instruction( + ConformsNode(test_res, expr, node.type.lex)) + self.register_instruction( + IfGotoNode(test_res, matching_label.label)) + self.register_instruction( + GotoNode(next_label.label) + ) + self.register_instruction(matching_label) + typex = self.context.get_type(node.type.lex) + var_info = scope.define_variable(node.id.lex, typex) + var_info.real_name = self.register_local(var_info) + self.register_instruction(AssignNode(var_info.real_name, expr)) + + case_action_expr = self.visit(node.expression, scope) + return case_action_expr + + @visitor.when(cool.LetInNode) + def visit(self, node: cool.LetInNode, scope: Scope): + let_scope = scope.create_child() + for var_decl in node.let_body: + self.visit(var_decl, let_scope) + + result = self.visit(node.in_body, let_scope) + return result + + @visitor.when(cool.LetVariableDeclaration) + def visit(self, node: cool.LetVariableDeclaration, scope: Scope): + var_info = scope.define_variable(node.id.lex, node.type) + var_info.real_name = self.register_local(var_info) + if node.expression: + value = self.visit(node.expression, scope) + self.register_instruction(AssignNode(var_info.real_name, value)) + else: + typex = node.type.lex + if typex == 'String': + result = self.register_data("").name + self.register_instruction( + AssignNode(var_info.real_name, result)) + else: + self.register_instruction(VoidNode(var_info.real_name)) + + @visitor.when(cool.FunctionCallNode) + def visit(self, node: cool.FunctionCallNode, scope): + name = None + if not (node.type): + typex = self.context.get_type(node.obj.static_type.name).name + else: + typex = node.type.lex + name = self.to_function_name(node.id.lex, typex) + result = self.define_internal_local() + + obj = self.visit(node.obj, scope) + if typex in ["Int", "Bool", "String"]: + # self.register_instruction(ArgNode(obj)) + packed = self.define_internal_local() + alloc = self.define_internal_local() + self.register_instruction(AllocateNode(alloc, typex)) + self.register_instruction(ArgNode(alloc)) + self.register_instruction(StaticCallNode(f"ctor_{typex}", alloc)) + self.register_instruction(EmptyArgs(1)) + self.register_instruction( + SetAttribNode(alloc, "value", obj, typex)) + obj = alloc + + rev_args = [] + for arg in node.args: + arg_value = self.visit(arg, scope) + # rev_args = rev_args + [arg_value] + rev_args = [arg_value] + rev_args + for arg_value in rev_args: + self.register_instruction(ArgNode(arg_value)) + + self.register_instruction(ArgNode(obj)) + if name: + self.register_instruction(StaticCallNode(name, result)) + else: + self.register_instruction( + DynamicCallNode(obj, typex, node.id.lex, result)) + + self.register_instruction(EmptyArgs(len(node.args) + 1)) + + return result + + @visitor.when(cool.MemberCallNode) + def visit(self, node: cool.MemberCallNode, scope: Scope): + type_name = self.current_type.name + result = self.define_internal_local() + rev_args = [] + for arg in node.args: + # FIXME: revert Args ???? + arg_value = self.visit(arg, scope) + # rev_args = rev_args + [arg_value] + rev_args = [arg_value] + rev_args + for arg_value in rev_args: + self.register_instruction(ArgNode(arg_value)) + self_inst = scope.find_variable('self').name + self.register_instruction(ArgNode(self_inst)) + self.register_instruction( + DynamicCallNode(self_inst, type_name, node.id.lex, result)) + + self.register_instruction(EmptyArgs(len(node.args) + 1)) + return result + + @visitor.when(cool.PlusNode) + def visit(self, node: cool.PlusNode, scope): + return self.define_binary_node(node, scope, PlusNode) + + @visitor.when(cool.MinusNode) + def visit(self, node: cool.MinusNode, scope): + return self.define_binary_node(node, scope, MinusNode) + + @visitor.when(cool.StarNode) + def visit(self, node: cool.StarNode, scope): + return self.define_binary_node(node, scope, StarNode) + + @visitor.when(cool.DivNode) + def visit(self, node: cool.DivNode, scope): + return self.define_binary_node(node, scope, DivNode) + + @visitor.when(cool.LessNode) + def visit(self, node: cool.LessNode, scope): + return self.define_binary_node(node, scope, LessNode) + + @visitor.when(cool.LessEqualNode) + def visit(self, node: cool.LessEqualNode, scope): + return self.define_binary_node(node, scope, LessEqNode) + + @visitor.when(cool.EqualNode) + def visit(self, node: cool.EqualNode, scope): + left = self.visit(node.left, scope) + right = self.visit(node.right, scope) + result = self.define_internal_local() + + if node.left.static_type == self.context.get_type('String'): + self.register_instruction(StringEqualNode(result, left, right)) + else: + self.register_instruction(EqualNode(result, left, right)) + return result + + @visitor.when(cool.IsVoidNode) + def visit(self, node: cool.IsVoidNode, scope): + return self.define_unary_node(node, scope, IsVoidNode) + + @visitor.when(cool.NotNode) + def visit(self, node: cool.NotNode, scope): + return self.define_unary_node(node, scope, NotNode) + + @visitor.when(cool.ComplementNode) + def visit(self, node: cool.ComplementNode, scope): + return self.define_unary_node(node, scope, ComplementNode) + + @visitor.when(cool.IdNode) + def visit(self, node: cool.IdNode, scope: Scope): + nvar = scope.find_variable(node.token.lex) + if not nvar: + selfx = scope.find_variable('self').name + nvar = self.define_internal_local() + self.register_instruction( + GetAttribNode(nvar, selfx, node.token.lex, self.current_type.name)) + else: + nvar = nvar.real_name + return nvar + + @visitor.when(cool.BoolNode) + def visit(self, node: cool.BoolNode, scope): + value = 1 if node.token.lex else 0 + bool_inst = self.define_internal_local() + self.register_instruction(BoxNode(bool_inst, value)) + return bool_inst + + @visitor.when(cool.IntegerNode) + def visit(self, node: cool.IntegerNode, scope): + value = int(node.token.lex) + int_inst = self.define_internal_local() + self.register_instruction(BoxNode(int_inst, value)) + return int_inst + + @visitor.when(cool.StringNode) + def visit(self, node: cool.StringNode, scope): + string = self.register_data(node.token.lex) + dest = self.define_internal_local() + self.register_instruction(LoadNode(dest, string.name)) + return dest diff --git a/src/engine/codegen/to_mips.py b/src/engine/codegen/to_mips.py new file mode 100644 index 00000000..837db300 --- /dev/null +++ b/src/engine/codegen/to_mips.py @@ -0,0 +1,767 @@ +from .cil_ast import * +from ..cp import visitor +from .mips import MipsCode, MemoryType, MipsLabel, VTable, GlobalDescriptor, word_size, string_max_size +from .mips import Registers as reg +from typing import Dict, List + + +class CIL_TO_MIPS: + + def __init__(self, data_size=4): + self.types = [] + # self.types_offsets: Dict[str, MemoryType] = dict() + self.arguments = {} + self.local_vars = {} + self.data_segment = [] + self.data_size = data_size + self.registers_to_save = [ + reg.ra, + reg.s0, + reg.s1, + reg.s2, + reg.s3, + reg.s4, + reg.s5, + reg.s6, + ] + self.label_count = 0 + self.vtable_reg = reg.s7 + self.mips = MipsCode() + + # def build_types(self, types): + # for idx, typex in enumerate(types): + # self.types_offsets[typex.name] = TypeData(idx, typex) + + def fill_vtable(self): + index = 0 + + self.mips.comment("Build VTable") + for name, tag in self.global_descriptor.vTable.methods.items(): + self.mips.comment(name) + self.mips.la(reg.s0, tag) + self.mips.store_memory(reg.s0, self.mips.offset( + self.vtable_reg, index*self.data_size)) + index += 1 + + def build_tags(self, dottypes: List[TypeNode]): + base_tag = "classname_" + + tags = dict() + + for dottype in dottypes: + name = base_tag + dottype.name + tags[dottype.name] = name + self.mips.data_label(name) + self.mips.asciiz(dottype.name) + + return tags + + def get_offset(self, arg: str): + if arg in self.arguments or arg in self.local_vars: + offset = ( + self.arguments[arg] + if arg in self.arguments + else self.local_vars[arg] + ) * 4 + return self.mips.offset(reg.fp, offset) + else: + raise Exception( + f"load_memory: The direction {arg} isn't an address") + + def get_label(self): + self.label_count += 1 + return f"mips_label_{self.label_count}" + + def load_memory(self, dst, arg: str): + self.mips.comment(f"Load from {arg} to {dst}") + if arg in self.arguments or arg in self.local_vars: + offset = ( + self.arguments[arg] + if arg in self.arguments + else self.local_vars[arg] + ) * self.data_size + self.mips.load_memory(dst, self.mips.offset(reg.fp, offset)) + elif arg in self.data_segment: + self.mips.la(dst, arg) + else: + raise Exception( + f"load_memory: The direction {arg} isn't an address") + + def store_memory(self, src, dst: str): + + self.mips.comment(f"from src: {src} to dst: {dst}") + if dst in self.arguments or dst in self.local_vars: + offset = ( + self.arguments[dst] + if dst in self.arguments + else self.local_vars[dst] + ) * self.data_size + offset = self.mips.offset(reg.fp, offset) + self.mips.store_memory(src, offset) + else: + raise Exception( + f"store_memory: The direction {dst} isn't an address") + self.mips.empty_line() + + def store_registers(self): + self.mips.comment("Saving Registers") + for reg in self.registers_to_save: + self.mips.push(reg) + + def load_registers(self): + for reg in reversed(self.registers_to_save): + self.mips.pop(reg) + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node: ProgramNode): + + tags = self.build_tags(node.dottypes) + + self.global_descriptor = GlobalDescriptor(node.dottypes, tags) + + for data in node.dotdata: + self.visit(data) + self.data_segment.append(data.name) + + self.mips.label('main') + self.mips.allocate_vtable( + self.global_descriptor.vTable.size(), self.vtable_reg) + + self.fill_vtable() + self.mips.jal('entry') + self.mips.empty_line() + self.mips.exit() + + for code in node.dotcode: + self.visit(code) + + @visitor.when(TypeNode) + def visit(self, node): + pass + + @visitor.when(FunctionNode) + def visit(self, node: FunctionNode): + self.mips.label(node.name) + + self.mips.comment("Set stack frame") + self.mips.push(reg.fp) + self.mips.move(reg.fp, reg.sp) + self.mips.empty_line() + + self.arguments = dict() + + for idx, param in enumerate(node.params): + self.visit(param, index=idx) + + self.mips.comment("Allocate memory for Local variables") + localvars_count = len(node.localvars) + self.mips.addi(reg.sp, reg.sp, - self.data_size * localvars_count) + self.mips.empty_line() + for idx, local in enumerate(node.localvars): + self.visit(local, index=idx) + + self.mips.empty_line() + self.store_registers() + self.mips.empty_line() + self.mips.comment("Generating body code") + for instruction in node.instructions: + self.visit(instruction) + + self.mips.empty_line() + self.mips.comment("Restore registers") + self.load_registers() + self.mips.empty_line() + + self.mips.comment("Clean stack variable space") + self.mips.addi(reg.sp, reg.sp, localvars_count * self.data_size) + self.arguments = None + self.mips.comment("Return") + self.mips.pop(reg.fp) + self.mips.jr(reg.ra) + self.mips.empty_line() + + @visitor.when(DataNode) + def visit(self, node: DataNode): + self.mips.data_label(node.name) + self.mips.asciiz(node.value) + + @visitor.when(ParamNode) + def visit(self, node: ParamNode, index=0): + self.arguments[node.name] = index + 1 + + @visitor.when(LocalNode) + def visit(self, node: LocalNode, index=0): + if node.name in self.local_vars: + pass + else: + self.local_vars[node.name] = -(index + 1) + + @visitor.when(GetAttribNode) + def visit(self, node: GetAttribNode): + self.mips.comment( + f"GetAttribNode {node.dest} = {node.obj}.{node.attrib} Type:{node.type}") + self.load_memory(reg.t0, node.obj) + # get type info + type_descritptor: MemoryType = self.global_descriptor.Types[node.type] + # get attr offset + offset = type_descritptor.get_attr_index(node.attrib) + # retrieve offset from memory + self.mips.load_memory(reg.t1, self.mips.offset( + reg.t0, offset * self.data_size)) + self.store_memory(reg.t1, node.dest) + + @visitor.when(SetAttribNode) + def visit(self, node: SetAttribNode): + self.mips.comment( + f"SetAttribNode {node.obj}.{node.attrib} Type:{node.type} = {node.value}") + # get type info + type_descritptor: MemoryType = self.global_descriptor.Types[node.type] + # get attr offset + offset = type_descritptor.get_attr_index(node.attrib) + # get object reference into s0 + self.load_memory(reg.s0, node.obj) + + if node.value in self.local_vars or node.value in self.arguments: + self.mips.comment(f"SET local var {node.value}") + self.load_memory(reg.s1, node.value) + else: + try: + value = int(node.value) + self.mips.li(reg.s1, value) + except ValueError: + if node.value in self.data_segment: + self.mips.comment(f"SET data {node.value}") + self.mips.la(reg.s1, node.value) + else: + raise Exception(f"Setattr: label {node.value} not found") + + self.mips.store_memory(reg.s1, self.mips.offset( + reg.s0, offset * self.data_size)) + + @visitor.when(AssignNode) + def visit(self, node: AssignNode): + self.load_memory(reg.t0, node.source) + self.store_memory(reg.t0, node.dest) + + @visitor.when(ComplementNode) + def visit(self, node: ComplementNode): + self.load_memory(reg.s0, node.expression) + self.mips.li(reg.s1, -1) + self.mips.mult(reg.s0, reg.s1) + self.mips.mflo(reg.s0) + self.store_memory(reg.s0, node.dest) + + @visitor.when(PlusNode) + def visit(self, node: PlusNode): + self.load_memory(reg.t0, node.left) + self.load_memory(reg.t1, node.right) + self.mips.add(reg.t2, reg.t0, reg.t1) + self.store_memory(reg.t2, node.dest) + + @visitor.when(MinusNode) + def visit(self, node: MinusNode): + self.load_memory(reg.t0, node.left) + self.load_memory(reg.t1, node.right) + self.mips.sub(reg.t2, reg.t0, reg.t1) + self.store_memory(reg.t2, node.dest) + + @visitor.when(StarNode) + def visit(self, node: StarNode): + self.load_memory(reg.t0, node.left) + self.load_memory(reg.t1, node.right) + self.mips.mult(reg.t0, reg.t1) + self.mips.mflo(reg.t0) + self.store_memory(reg.t0, node.dest) + + @visitor.when(DivNode) + def visit(self, node: DivNode): + self.load_memory(reg.t0, node.left) + self.load_memory(reg.t1, node.right) + self.mips.div(reg.t2, reg.t0, reg.t1) + self.mips.mflo(reg.t0) + self.store_memory(reg.t0, node.dest) + + @visitor.when(EqualNode) + def visit(self, node: EqualNode): + self.load_memory(reg.t0, node.left) + self.load_memory(reg.t1, node.right) + self.mips.slt(reg.t2, reg.t0, reg.t1) + self.mips.slt(reg.t3, reg.t1, reg.t0) + + self.mips.add(reg.t0, reg.t2, reg.t3) + self.mips.slti(reg.t1, reg.t0, 1) + + self.store_memory(reg.t1, node.dest) + + @visitor.when(LessEqNode) + def visit(self, node: LessEqNode): + self.load_memory(reg.t0, node.left) + self.load_memory(reg.t1, node.right) + self.mips.slt(reg.t2, reg.t1, reg.t0) + self.mips.li(reg.t3, 1) + self.mips.sub(reg.t0, reg.t3, reg.t2) + self.store_memory(reg.t0, node.dest) + + @visitor.when(LessNode) + def visit(self, node: LessNode): + self.load_memory(reg.t0, node.left) + self.load_memory(reg.t1, node.right) + self.mips.slt(reg.t2, reg.t0, reg.t1) + self.store_memory(reg.t2, node.dest) + + @visitor.when(IsVoidNode) + def visit(self, node: IsVoidNode): + self.mips.comment("IsVoidNode") + self.load_memory(reg.t0, node.expression) + + label = self.get_label() + + self.mips.li(reg.t1, 0) + self.mips.bne(reg.t0, reg.t1, label) + self.mips.li(reg.t1, 1) + self.mips.label(label) + self.store_memory(reg.t1, node.dest) + + @visitor.when(NotNode) + def visit(self, node: NotNode): + self.mips.comment("NotNode") + self.load_memory(reg.s0, node.expression) + self.mips.li(reg.s1, 1) + self.mips.sub(reg.s2, reg.s1, reg.s0) + self.store_memory(reg.s2, node.dest) + + @visitor.when(AllocateNode) + def visit(self, node: AllocateNode): + # ---------- + # | ID | + # ---------- + # | Size | + # ---------- + # |Ptr_Name| + # ---------- + # |Ptr_Vtbl| + # ---------- + # | Attr1 | + # ---------- + # | Attr2 | + # .......... + # .......... + # + # s1 start addr of the class + # + self.mips.comment(f"Allocate space for {node.type}") + type_descritptor: MemoryType = self.global_descriptor.Types[node.type] + + length = type_descritptor.size() + length *= self.data_size + + # sbrk call + self.mips.li(reg.a0, length) + self.mips.sbrk() + self.mips.move(reg.s1, reg.v0) + + # pass object reference to node.dest + self.store_memory(reg.s1, node.dest) + + # Store Class ID + self.mips.li(reg.s0, type_descritptor.id) + self.mips.store_memory(reg.s0, self.mips.offset(reg.s1)) + + # Store Class size + self.mips.li(reg.s0, length) + self.mips.store_memory( + reg.s0, self.mips.offset(reg.s1, self.data_size)) + + # Store Class Name Ptr + self.mips.la(reg.s0, type_descritptor.ptr_name) + self.mips.store_memory( + reg.s0, self.mips.offset(reg.s1, 2 * self.data_size)) + + # Store Class Vtable Ptr + self.mips.li(reg.s0, type_descritptor.vtable * + self.data_size) # first function on vtable + self.mips.store_memory( + reg.s0, self.mips.offset(reg.s1, 3 * self.data_size)) + + # Reserve Attrs Space + for number, _ in enumerate(type_descritptor.attrs): + _offset = 4 + number + self.mips.store_memory(reg.zero, self.mips.offset( + reg.s1, _offset * self.data_size)) + + @visitor.when(TypeOfNode) + def visit(self, node: TypeOfNode): + self.mips.comment(f"TypeOfNode of {node.obj} to {node.dest}") + # Cargar la direccion de memoria + self.load_memory(reg.s0, node.obj) + # El offset 0 para el numero del tipo + self.mips.load_memory(reg.s1, self.mips.offset(reg.s0)) + self.store_memory(reg.s1, node.dest) + + @visitor.when(LabelNode) + def visit(self, node: LabelNode): + self.mips.label(node.label) + + @visitor.when(GotoNode) + def visit(self, node: GotoNode): + self.mips.comment("GotoNode") + self.mips.j(node.label) + + @visitor.when(IfGotoNode) + def visit(self, node: IfGotoNode): + self.mips.comment("IfGotoNode") + self.load_memory(reg.t0, node.value) + self.mips.li(reg.t1, 0) + self.mips.bne(reg.t0, reg.t1, node.label) + + @visitor.when(StaticCallNode) + def visit(self, node: StaticCallNode): + self.mips.comment("StaticCallNode") + self.mips.jal(node.function) + self.store_memory(reg.v0, node.dest) + + @visitor.when(DynamicCallNode) + def visit(self, node: DynamicCallNode): + self.mips.comment(f"DynamicCallNode {node.type} {node.method}") + type_descritptor: MemoryType = self.global_descriptor.Types[node.type] + + # self.mips.move(reg.a0, reg.s7) + # self.mips.syscall(1) + + offset = type_descritptor.get_method_index( + node.method) * self.data_size + self.load_memory(reg.s0, node.obj) + + # vtable ptr in position 4 (0 .. 3) + self.mips.load_memory( + reg.s1, self.mips.offset(reg.s0, 3 * self.data_size)) + + # print(type_descritptor.get_method_index(node.method)) + self.mips.addi(reg.s2, reg.s1, offset) + self.mips.addu(reg.s3, reg.s2, reg.s7) + + # retrieve function location + self.mips.load_memory(reg.s4, self.mips.offset(reg.s3)) + + # retrieve result from v0 + self.mips.jalr(reg.s4) + self.store_memory(reg.v0, node.dest) + + @visitor.when(ArgNode) + def visit(self, node: ArgNode): + self.mips.comment(f"ArgNode {node.name} to s0") + self.load_memory(reg.s0, node.name) + self.mips.push(reg.s0) + + @visitor.when(ErrorNode) + def visit(self, node: ErrorNode): + self.mips.comment("ErrorNode") + self.mips.li(reg.a0, 1) + self.mips.syscall(17) + + @visitor.when(BoxNode) + def visit(self, node: BoxNode): + self.mips.li(reg.s0, node.value) + self.store_memory(reg.s0, node.dest) + + @visitor.when(AbortNode) + def visit(self, node: AbortNode): + self.mips.exit() + self.mips.empty_line() + + def copy_data(self, src, dst, length): + """ + length: fixed in bytes size. + """ + loop = self.get_label() + end = self.get_label() + + self.mips.move(reg.t0, src) + self.mips.move(reg.t1, dst) + self.mips.move(reg.t3, length) # i = length + + self.mips.label(loop) + + self.mips.lb(reg.t2, self.mips.offset(reg.t0)) + self.mips.sb(reg.t2, self.mips.offset(reg.t1)) + + self.mips.addi(reg.t0, reg.t0, 2) + self.mips.addi(reg.t1, reg.t1, 2) + + self.mips.addi(reg.t3, reg.t3, -1) # i -- + + self.mips.beqz(reg.t3, end) + self.mips.j(loop) + + self.mips.label(end) + + @visitor.when(CopyNode) + def visit(self, node): + self.mips.comment(f"Copy Node {node.dest} {node.obj}") + # load object + self.load_memory(reg.s0, node.obj) + # load size + self.mips.load_memory(reg.s1, self.mips.offset(reg.s0, self.data_size)) + # load dest + self.load_memory(reg.s3, node.dest) + # copy byte to byte + self.copy_data(reg.s0, reg.s3, reg.s1) + + @visitor.when(TypeNameNode) + def visit(self, node: TypeNameNode): + self.mips.comment(f"TypeNameNode {node.dest} Type:{node.type}") + self.load_memory(reg.t0, node.type) + # ptr at 3rd position in memory ( 2 in base 0) + self.mips.load_memory( + reg.t1, self.mips.offset(reg.t0, 2 * self.data_size)) + self.store_memory(reg.t1, node.dest) + + def get_string_length(self, src, dst): + loop = self.get_label() + end = self.get_label() + + self.mips.move(reg.t0, src) + self.mips.li(reg.t1, 0) + + self.mips.label(loop) + + self.mips.lb(reg.t3, self.mips.offset(reg.t0)) + self.mips.beqz(reg.t3, end) + + self.mips.addi(reg.t1, reg.t1, 1) + self.mips.addi(reg.t0, reg.t0, 1) + + self.mips.j(loop) + self.mips.label(end) + + self.mips.move(dst, reg.t1) + + @visitor.when(LengthNode) + def visit(self, node: LengthNode): + self.mips.comment("LengthNode") + self.load_memory(reg.s1, node.msg) + self.get_string_length(reg.s1, reg.s0) + self.store_memory(reg.s0, node.dest) + + def copy_str(self, src, dst, result): + loop = self.get_label() + end = self.get_label() + + self.mips.move(reg.t0, src) + self.mips.move(reg.t1, dst) + + self.mips.label(loop) + + self.mips.lb(reg.t2, self.mips.offset(reg.t0)) + self.mips.sb(reg.t2, self.mips.offset(reg.t1)) + + self.mips.beqz(reg.t2, end) + + self.mips.addi(reg.t0, reg.t0, 1) + self.mips.addi(reg.t1, reg.t1, 1) + + self.mips.j(loop) + self.mips.label(end) + + self.mips.move(result, reg.t1) + + @visitor.when(ConcatNode) + def visit(self, node: ConcatNode): + + self.load_memory(reg.s0, node.msg1) + self.load_memory(reg.s1, node.msg2) + + self.get_string_length(reg.s0, reg.s4) + self.get_string_length(reg.s1, reg.s5) + + self.mips.add(reg.a0, reg.s4, reg.s5) + self.mips.addi(reg.a0, reg.a0, 1) + self.mips.sbrk() + self.mips.move(reg.s3, reg.v0) + + self.copy_str(reg.s0, reg.s3, reg.v0) + self.copy_str(reg.s1, reg.v0, reg.v0) + + self.store_memory(reg.s3, node.dest) + + @visitor.when(StringEqualNode) + def visit(self, node: StringEqualNode): + self.mips.empty_line() + self.mips.comment('Comparing Strings --') + end_label = self.get_label() + end_ok_label = self.get_label() + end_wrong_label = self.get_label() + loop_label = self.get_label() + self.load_memory(reg.s0, node.msg1) + + # self.mips.move(reg.a0, reg.s0) + # self.mips.syscall(1) + + self.load_memory(reg.s1, node.msg2) + + self.mips.move(reg.t8, reg.s0) + self.mips.move(reg.t9, reg.s1) + + self.mips.label(loop_label) + # me parece q aki esta fallando xq esta cargando un "0" + # en $t8, y cuando le pide el offset, no tiene nada, hay q ver ahi + # pero con el "1" hace lo mismo + + self.mips.lb(reg.a0, self.mips.offset(reg.t8)) + self.mips.lb(reg.a1, self.mips.offset(reg.t9)) + + self.mips.beqz(reg.a0, end_ok_label) + self.mips.beqz(reg.a1, end_wrong_label) + self.mips.seq(reg.v0, reg.a0, reg.a1) + self.mips.beqz(reg.v0, end_wrong_label) + + self.mips.addi(reg.t8, reg.t8, 1) + self.mips.addi(reg.t9, reg.t9, 1) + self.mips.j(loop_label) + + self.mips.label(end_wrong_label) + self.mips.li(reg.v0, 0) + self.mips.j(end_label) + self.mips.label(end_ok_label) + self.mips.bnez(reg.a1, end_wrong_label) + self.mips.li(reg.v0, 1) + self.mips.label(end_label) + + self.store_memory(reg.v0, node.dest) + + @visitor.when(LoadNode) + def visit(self, node: LoadNode): + self.load_memory(reg.s0, node.msg) + self.store_memory(reg.s0, node.dest) + + def copy_substr(self, src, dst, length): + loop = self.get_label() + end = self.get_label() + + self.mips.move(reg.t0, src) + self.mips.move(reg.t1, dst) + + self.mips.move(reg.t3, length) + + self.mips.label(loop) + + self.mips.lb(reg.t2, self.mips.offset(reg.t0)) + self.mips.sb(reg.t2, self.mips.offset(reg.t1)) + + self.mips.addi(reg.t0, reg.t0, 1) + self.mips.addi(reg.t1, reg.t1, 1) + + self.mips.addi(reg.t3, reg.t3, -1) + + self.mips.beqz(reg.t3, end) + self.mips.j(loop) + + self.mips.label(end) + + self.mips.move(reg.t2, reg.zero) + self.mips.sb(reg.t2, self.mips.offset(reg.t1)) + + @visitor.when(SubstringNode) + def visit(self, node): + + self.load_memory(reg.s0, node.msg1) + self.load_memory(reg.s1, node.length) + self.load_memory(reg.s3, node.start) + + self.mips.add(reg.s0, reg.s0, reg.s3) + + self.mips.move(reg.a0, reg.s1) + self.mips.addi(reg.a0, reg.a0, 1) + self.mips.sbrk() + self.copy_substr(reg.s0, reg.v0, reg.s1) + + self.store_memory(reg.v0, node.dest) + + @visitor.when(ReadStrNode) + def visit(self, node): + self.mips.li(reg.a0, 1024) + self.mips.sbrk() + self.mips.move(reg.a0, reg.v0) + self.store_memory(reg.v0, node.dest) + self.mips.li(reg.a1, 1024) + self.mips.read_string() + + self.mips.empty_line() + self.mips.comment("Remove last character from string") + + start = self.get_label() + end = self.get_label() + second_end = self.get_label() + + self.mips.label(start) + # load byte by byte + self.mips.lb(reg.s2, self.mips.offset(reg.a0)) + # jump end if reached end line + self.mips.beq(reg.s2, 0, end) + # pointer += 1 + self.mips.addi(reg.a0, reg.a0, 1) + self.mips.j(start) + self.mips.label(end) + # go back 1 position + self.mips.addi(reg.a0, reg.a0, -1) + self.mips.lb(reg.s3, self.mips.offset(reg.a0)) + self.mips.li(reg.s4, 10) + self.mips.bne(reg.s3, reg.s4, second_end) + # change /n to /0 + self.mips.sb(reg.zero, self.mips.offset(reg.a0)) + self.mips.label(second_end) + + @visitor.when(PrintStrNode) + def visit(self, node: PrintStrNode): + self.mips.comment(f"Print str {node.str_addr}") + self.load_memory(reg.a0, node.str_addr) + self.mips.print_str(node.str_addr) + + @visitor.when(ReadIntNode) + def visit(self, node: ReadIntNode): + self.mips.read_int() + self.store_memory(reg.v0, node.dest) + + @visitor.when(PrintIntNode) + def visit(self, node: PrintIntNode): + self.load_memory(reg.a0, node.str_addr) + self.mips.print_int(node.str_addr) + + @visitor.when(EmptyArgs) + def visit(self, node: EmptyArgs): + self.mips.addi(reg.sp, reg.sp, node.args * self.data_size) + + @visitor.when(ReturnNode) + def visit(self, node: ReturnNode): + self.mips.comment("ReturnNode") + self.load_memory(reg.v0, node.value) + + @visitor.when(VoidNode) + def visit(self, node: VoidNode): + self.store_memory(reg.zero, node.dest) + + @visitor.when(ConformsNode) + def visit(self, node: ConformsNode): + self.mips.comment( + f"Conforms Node {node.dest} = {node.type} {node.expr}") + _id = self.global_descriptor.Types[node.type].id + self.load_memory(reg.s0, node.expr) + self.mips.load_memory(reg.s1, self.mips.offset(reg.s0)) + self.mips.empty_line() + + self.mips.li(reg.s2, _id) + + one = self.get_label() + end = self.get_label() + + self.mips.beq(reg.s1, reg.s2, one) + self.store_memory(reg.zero, node.dest) + self.mips.j(end) + self.mips.label(one) + self.mips.li(reg.s3, 1) + self.store_memory(reg.s3, node.dest) + self.mips.label(end) diff --git a/src/engine/commons/__init__.py b/src/engine/commons/__init__.py new file mode 100644 index 00000000..bec48162 --- /dev/null +++ b/src/engine/commons/__init__.py @@ -0,0 +1 @@ +from .tokens import * diff --git a/src/engine/commons/tokens.py b/src/engine/commons/tokens.py new file mode 100644 index 00000000..3a78d0df --- /dev/null +++ b/src/engine/commons/tokens.py @@ -0,0 +1,69 @@ +####### Tokens ####### + +keywords = ( + 'CLASS', + 'ELSE', + # false case is independently treated + 'FI', + 'IF', + 'IN', + 'INHERITS', + 'ISVOID', + 'LET', + 'LOOP', + 'POOL', + 'THEN', + 'WHILE', + 'CASE', + 'ESAC', + 'NEW', + 'OF', + 'NOT' + # true case is independently treated +) + +literals = ['+', '-', '*', '/', ':', ';', '(', ')', '{', '}', '@', '.', ','] +# ['+', '-', '*', '/', ':', ';', '(', ')', '{', '}', '@', '.', ','] +terminals = { + r'\(': 'OPAR', + r'\)': 'CPAR', + r'\{': 'OCURL', + r'\}': 'CCURL', + r'\:': 'COLON', + r'\,': 'COMMA', + r'\.': 'DOT', + r'\;': 'SEMI', + r'\@': 'AT', + r'\*': 'STAR', + r'\/': 'DIV', + r'\+': 'PLUS', + r'\-': 'MINUS', + 'class': 'CLASS', + 'else': 'ELSE', + 'fi': 'FI', + 'if': 'IF', + 'in': 'IN', + 'inherits': 'INHERITS', + 'isvoid': 'ISVOID', + 'let': 'LET', + 'loop': 'LOOP', + 'pool': 'POOL', + 'then': 'THEN', + 'while': 'WHILE', + 'case': 'CASE', + 'esac': 'ESAC', + 'new': 'NEW', + 'of': 'OF', + 'not': 'NOT', +} + +tokens = ( + # Identifiers + 'TYPE', 'ID', + # Primitive data types + 'INTEGER', 'STRING', 'BOOL', + # Special keywords + 'ACTION', + # Operators + 'ASSIGN', 'LESS', 'LESSEQUAL', 'EQUAL', 'INT_COMPLEMENT', +) diff --git a/src/engine/cp/__init__.py b/src/engine/cp/__init__.py new file mode 100644 index 00000000..10d8ca17 --- /dev/null +++ b/src/engine/cp/__init__.py @@ -0,0 +1,7 @@ +from .automata import * +from .evaluation import * +from .grammartools import * +from .pycompiler import * +from .semantic import * +from .utils import * +from .visitor import * \ No newline at end of file diff --git a/src/engine/cp/automata.py b/src/engine/cp/automata.py new file mode 100644 index 00000000..0b986338 --- /dev/null +++ b/src/engine/cp/automata.py @@ -0,0 +1,208 @@ +try: + import pydot +except: + pass + +class State: + def __init__(self, state, final=False, formatter=lambda x: str(x)): + self.state = state + self.final = final + self.transitions = {} + self.epsilon_transitions = set() + self.tag = None + self.formatter = formatter + + def set_formatter(self, formatter, visited=None): + if visited is None: + visited = set() + elif self in visited: + return + + visited.add(self) + self.formatter = formatter + for destinations in self.transitions.values(): + for node in destinations: + node.set_formatter(formatter, visited) + for node in self.epsilon_transitions: + node.set_formatter(formatter, visited) + return self + + def has_transition(self, symbol): + return symbol in self.transitions + + def add_transition(self, symbol, state): + try: + self.transitions[symbol].append(state) + except: + self.transitions[symbol] = [state] + return self + + def add_epsilon_transition(self, state): + self.epsilon_transitions.add(state) + return self + + def recognize(self, string): + states = self.epsilon_closure + for symbol in string: + states = self.move_by_state(symbol, *states) + states = self.epsilon_closure_by_state(*states) + return any(s.final for s in states) + + def to_deterministic(self, formatter=lambda x: str(x)): + closure = self.epsilon_closure + start = State(tuple(closure), any(s.final for s in closure), formatter) + + closures = [ closure ] + states = [ start ] + pending = [ start ] + + while pending: + state = pending.pop() + symbols = { symbol for s in state.state for symbol in s.transitions } + + for symbol in symbols: + move = self.move_by_state(symbol, *state.state) + closure = self.epsilon_closure_by_state(*move) + + if closure not in closures: + new_state = State(tuple(closure), any(s.final for s in closure), formatter) + closures.append(closure) + states.append(new_state) + pending.append(new_state) + else: + index = closures.index(closure) + new_state = states[index] + + state.add_transition(symbol, new_state) + + return start + + @staticmethod + def from_nfa(nfa, get_states=False): + states = [] + for n in range(nfa.states): + state = State(n, n in nfa.finals) + states.append(state) + + for (origin, symbol), destinations in nfa.map.items(): + origin = states[origin] + origin[symbol] = [ states[d] for d in destinations ] + + if get_states: + return states[nfa.start], states + return states[nfa.start] + + @staticmethod + def move_by_state(symbol, *states): + return { s for state in states if state.has_transition(symbol) for s in state[symbol]} + + @staticmethod + def epsilon_closure_by_state(*states): + closure = { state for state in states } + + l = 0 + while l != len(closure): + l = len(closure) + tmp = [s for s in closure] + for s in tmp: + for epsilon_state in s.epsilon_transitions: + closure.add(epsilon_state) + return closure + + @property + def epsilon_closure(self): + return self.epsilon_closure_by_state(self) + + @property + def name(self): + return f'{self.tag}\n{self.formatter(self.state)}' if self.tag else self.formatter(self.state) + + def get(self, symbol): + target = self.transitions[symbol] + assert len(target) == 1 + return target[0] + + def __getitem__(self, symbol): + if symbol == '': + return self.epsilon_transitions + try: + return self.transitions[symbol] + except KeyError: + return None + + def __setitem__(self, symbol, value): + if symbol == '': + self.epsilon_transitions = value + else: + self.transitions[symbol] = value + + def __repr__(self): + return str(self) + + def __str__(self): + return str(self.state) + + def __hash__(self): + return hash(self.state) + + def __iter__(self): + yield from self._visit() + + def _visit(self, visited=None): + if visited is None: + visited = set() + elif self in visited: + return + + visited.add(self) + yield self + + for destinations in self.transitions.values(): + for node in destinations: + yield from node._visit(visited) + for node in self.epsilon_transitions: + yield from node._visit(visited) + + def graph(self): + G = pydot.Dot(rankdir='LR', margin=0.1) + G.add_node(pydot.Node('start', shape='plaintext', label='', width=0, height=0)) + + visited = set() + def visit(start): + ids = id(start) + if ids not in visited: + visited.add(ids) + G.add_node(pydot.Node(ids, label=start.name, shape='circle', style='bold' if start.final else '')) + for tran, destinations in start.transitions.items(): + for end in destinations: + visit(end) + G.add_edge(pydot.Edge(ids, id(end), label=tran, labeldistance=2)) + for end in start.epsilon_transitions: + visit(end) + G.add_edge(pydot.Edge(ids, id(end), label='ε', labeldistance=2)) + + visit(self) + G.add_edge(pydot.Edge('start', id(self), label='', style='dashed')) + + return G + + def _repr_svg_(self): + try: + return self.graph().create_svg().decode('utf8') + except: + pass + + def write_to(self, fname): + return self.graph().write_svg(fname) + +def multiline_formatter(state): + return '\n'.join(str(item) for item in state) + +def lr0_formatter(state): + try: + return '\n'.join(str(item)[:-4] for item in state) + except TypeError: + return str(state)[:-4] + +def empty_formatter(state): + return '' \ No newline at end of file diff --git a/src/engine/cp/evaluation.py b/src/engine/cp/evaluation.py new file mode 100644 index 00000000..e0d0e808 --- /dev/null +++ b/src/engine/cp/evaluation.py @@ -0,0 +1,34 @@ +from .pycompiler import EOF +from .grammartools import ShiftReduceParser, Action + +def evaluate_reverse_parse(right_parse, operations, tokens): + if not right_parse or not operations or not tokens: + return + + right_parse = iter(right_parse) + tokens = iter(tokens) + stack = [] + for operation in operations: + if operation == Action.SHIFT: + token = next(tokens) + # stack.append(token.lex) + stack.append(token) + elif operation == Action.REDUCE: + production = next(right_parse) + head, body = production + attributes = production.attributes + assert all(rule is None for rule in attributes[1:]), 'There must be only synteticed attributes.' + rule = attributes[0] + + if len(body): + synteticed = [None] + stack[-len(body):] + value = rule(None, synteticed) + stack[-len(body):] = [value] + else: + stack.append(rule(None, None)) + else: + raise Exception('Invalid action!!!') + + assert len(stack) == 1 + assert isinstance(next(tokens).token_type, EOF) + return stack[0] \ No newline at end of file diff --git a/src/engine/cp/grammartools.py b/src/engine/cp/grammartools.py new file mode 100644 index 00000000..c9b842d6 --- /dev/null +++ b/src/engine/cp/grammartools.py @@ -0,0 +1,325 @@ +from queue import Queue +from .pycompiler import Grammar, Item +from .automata import State +from .utils import ContainerSet + +class GrammarTools: + @staticmethod + def compute_local_first(firsts, alpha): + """ + Computes First(alpha), given First(Vt) and First(Vn) + alpha in (Vt U Vn)* + """ + first_alpha = ContainerSet() + + try: + alpha_is_epsilon = alpha.IsEpsilon + except: + alpha_is_epsilon = False + + # alpha == epsilon ? First(alpha) = { epsilon } + if alpha_is_epsilon: + first_alpha.set_epsilon() + + # alpha = X1 ... XN + # First(Xi) subset of First(alpha) + # epsilon in First(X1)...First(Xi) ? First(Xi+1) subset of First(X) & First(alpha) + # epsilon in First(X1)...First(XN) ? epsilon in First(X) & First(alpha) + else: + for symbol in alpha: + first_symbol = firsts[symbol] + first_alpha.update(first_symbol) + if not first_symbol.contains_epsilon: + break + else: + first_alpha.set_epsilon() + + return first_alpha + + @staticmethod + def compute_firsts(G: Grammar): + """ + Computes First(Vt) U First(Vn) U First(alpha) + P: X -> alpha + """ + firsts = {} + change = True + + # init First(Vt) + for terminal in G.terminals: + firsts[terminal] = ContainerSet(terminal) + + # init First(Vn) + for nonterminal in G.nonTerminals: + firsts[nonterminal] = ContainerSet() + + while change: + change = False + + # P: X -> alpha + for production in G.Productions: + X = production.Left + alpha = production.Right + + # get current First(X) + first_X = firsts[X] + + # init First(alpha) + try: + first_alpha = firsts[alpha] + except: + first_alpha = firsts[alpha] = ContainerSet() + + # CurrentFirst(alpha)??? + local_first = GrammarTools.compute_local_first(firsts, alpha) + + # update First(X) and First(alpha) from CurrentFirst(alpha) + change |= first_alpha.hard_update(local_first) + change |= first_X.hard_update(local_first) + + # First(Vt) + First(Vt) + First(RightSides) + return firsts + + @staticmethod + def compute_follows(G: Grammar, firsts): + """ + Computes Follow(Vn) + """ + follows = { } + change = True + + local_firsts = {} + + # init Follow(Vn) + for nonterminal in G.nonTerminals: + follows[nonterminal] = ContainerSet() + follows[G.startSymbol] = ContainerSet(G.EOF) + + while change: + change = False + + # P: X -> alpha + for production in G.Productions: + X = production.Left + alpha = production.Right + + follow_X = follows[X] + + # X -> zeta Y beta + # First(beta) - { epsilon } subset of Follow(Y) + # beta ->* epsilon or X -> zeta Y ? Follow(X) subset of Follow(Y) + for i, symbol in enumerate(alpha): + if symbol.IsNonTerminal: + follow_symbol = follows[symbol] + beta = alpha[i + 1:] + try: + first_beta = local_firsts[beta] + except KeyError: + first_beta = local_firsts[beta] = GrammarTools.compute_local_first(firsts, beta) + change |= follow_symbol.update(first_beta) + if first_beta.contains_epsilon or len(beta) == 0: + change |= follow_symbol.update(follow_X) + + return follows + + @staticmethod + def _register(table, state, symbol, value): + if state not in table: + table[state] = dict() + + row = table[state] + + if symbol not in row: + row[symbol] = [] + + cell = row[symbol] + + if value not in cell: + cell.append(value) + + return len(cell) == 1 + +class Action(tuple): + SHIFT = 'SHIFT' + REDUCE = 'REDUCE' + OK = 'OK' + + def __str__(self): + try: + action, tag = self + return f"{'S' if action == Action.SHIFT else 'OK' if action == Action.OK else ''}{tag}" + except: + return str(tuple(self)) + + __repr__ = __str__ + +class ShiftReduceParser: + def __init__(self, G, verbose=False): + self.G = G + self.verbose = verbose + self.action = {} + self.goto = {} + self._build_parsing_table() + + def _build_parsing_table(self): + raise NotImplementedError() + + def __call__(self, w): + stack = [ 0 ] + cursor = 0 + output, operations = [], [] + + while True: + state = stack[-1] + lookahead = w[cursor].token_type + if self.verbose: print(stack, w[cursor:]) + + # (Detect error) + try: + action, tag = self.action[state][lookahead][0] + # (Shift case) + if action == Action.SHIFT: + stack.append(tag) + cursor += 1 + operations.append(action) + # (Reduce case) + elif action == Action.REDUCE: + for _ in range(len(tag.Right)): stack.pop() + stack.append(self.goto[stack[-1]][tag.Left][0]) + output.append(tag) + operations.append(action) + # (OK case) + elif action == Action.OK: + # output.reverse() + return output, operations + # (Invalid case) + else: + assert False, 'Must be something wrong!' + except KeyError: + if self.verbose: + print('Parsing Error:', stack, w[cursor:]) + return w[cursor:][0], None + +class LR1Parser(ShiftReduceParser): + @staticmethod + def expand(item, firsts): + next_symbol = item.NextSymbol + if next_symbol is None or not next_symbol.IsNonTerminal: + return [] + + lookaheads = ContainerSet() + # (Compute lookahead for child items) + for preview in item.Preview(): + lookaheads.hard_update(GrammarTools.compute_local_first(firsts, preview)) + + assert not lookaheads.contains_epsilon + # (Build and return child items) + return [Item(prod, 0, lookaheads) for prod in next_symbol.productions] + + @staticmethod + def compress(items): + centers = {} + + for item in items: + center = item.Center() + try: + lookaheads = centers[center] + except KeyError: + centers[center] = lookaheads = set() + lookaheads.update(item.lookaheads) + + return { Item(x.production, x.pos, set(lookahead)) for x, lookahead in centers.items() } + + @staticmethod + def closure_lr1(items, firsts): + closure = ContainerSet(*items) + + changed = True + while changed: + changed = False + + new_items = ContainerSet() + for item in closure: + new_items.extend(LR1Parser.expand(item, firsts)) + + changed = closure.update(new_items) + + return LR1Parser.compress(closure) + + @staticmethod + def goto_lr1(items, symbol, firsts=None, just_kernel=False): + assert just_kernel or firsts is not None, '`firsts` must be provided if `just_kernel=False`' + items = frozenset(item.NextItem() for item in items if item.NextSymbol == symbol) + return items if just_kernel else LR1Parser.closure_lr1(items, firsts) + + + def build_LR1_automaton(self): + G = self.augmentedG = self.G.AugmentedGrammar(True) + + firsts = GrammarTools.compute_firsts(G) + firsts[G.EOF] = ContainerSet(G.EOF) + + start_production = G.startSymbol.productions[0] + start_item = Item(start_production, 0, lookaheads=(G.EOF,)) + start = frozenset([start_item]) + + closure = LR1Parser.closure_lr1(start, firsts) + automaton = State(frozenset(closure), True) + + pending = [ start ] + visited = { start: automaton } + + while pending: + current = pending.pop() + current_state = visited[current] + + for symbol in G.terminals + G.nonTerminals: + # (Get/Build `next_state`) + kernels = LR1Parser.goto_lr1(current_state.state, symbol, just_kernel=True) + + if not kernels: + continue + + try: + next_state = visited[kernels] + except KeyError: + pending.append(kernels) + visited[pending[-1]] = next_state = State(frozenset(LR1Parser.goto_lr1(current_state.state, symbol, firsts)), True) + + current_state.add_transition(symbol.Name, next_state) + + # automaton.set_formatter(empty_formatter) + self.automaton = automaton + + def _build_parsing_table(self): + self.is_lr1 = True + self.build_LR1_automaton() + + for i, node in enumerate(self.automaton): + if self.verbose: print(i, '\t', '\n\t '.join(str(x) for x in node.state), '\n') + node.idx = i + node.tag = f'I{i}' + + for node in self.automaton: + idx = node.idx + for item in node.state: + # - Fill `self.Action` and `self.Goto` according to `item`) + # - Feel free to use `self._register(...)`) + if item.IsReduceItem: + prod = item.production + if prod.Left == self.augmentedG.startSymbol: + self.is_lr1 &= GrammarTools._register(self.action, idx, self.augmentedG.EOF, + Action((Action.OK, ''))) + else: + for lookahead in item.lookaheads: + self.is_lr1 &= GrammarTools._register(self.action, idx, lookahead, + Action((Action.REDUCE, prod))) + else: + next_symbol = item.NextSymbol + if next_symbol.IsTerminal: + self.is_lr1 &= GrammarTools._register(self.action, idx, next_symbol, + Action((Action.SHIFT, node[next_symbol.Name][0].idx))) + else: + self.is_lr1 &= GrammarTools._register(self.goto, idx, next_symbol, + node[next_symbol.Name][0].idx) + pass \ No newline at end of file diff --git a/src/engine/cp/pycompiler.py b/src/engine/cp/pycompiler.py new file mode 100644 index 00000000..bba9423d --- /dev/null +++ b/src/engine/cp/pycompiler.py @@ -0,0 +1,519 @@ +import json + +class Symbol(object): + + def __init__(self, name, grammar): + self.Name = name + self.Grammar = grammar + + def __str__(self): + return self.Name + + def __repr__(self): + return repr(self.Name) + + def __add__(self, other): + if isinstance(other, Symbol): + return Sentence(self, other) + + raise TypeError(other) + + def __or__(self, other): + + if isinstance(other, (Sentence)): + return SentenceList(Sentence(self), other) + + raise TypeError(other) + + @property + def IsEpsilon(self): + return False + + def __len__(self): + return 1 + +class NonTerminal(Symbol): + + + def __init__(self, name, grammar): + super().__init__(name, grammar) + self.productions = [] + + + def __imod__(self, other): + + if isinstance(other, (Sentence)): + p = Production(self, other) + self.Grammar.Add_Production(p) + return self + + if isinstance(other, tuple): + assert len(other) > 1 + + if len(other) == 2: + other += (None,) * len(other[0]) + + assert len(other) == len(other[0]) + 2, "Debe definirse una, y solo una, regla por cada símbolo de la producción" + # assert len(other) == 2, "Tiene que ser una Tupla de 2 elementos (sentence, attribute)" + + if isinstance(other[0], Symbol) or isinstance(other[0], Sentence): + p = AttributeProduction(self, other[0], other[1:]) + else: + raise Exception("") + + self.Grammar.Add_Production(p) + return self + + if isinstance(other, Symbol): + p = Production(self, Sentence(other)) + self.Grammar.Add_Production(p) + return self + + if isinstance(other, SentenceList): + + for s in other: + p = Production(self, s) + self.Grammar.Add_Production(p) + + return self + + raise TypeError(other) + + @property + def IsTerminal(self): + return False + + @property + def IsNonTerminal(self): + return True + + @property + def IsEpsilon(self): + return False + +class Terminal(Symbol): + + def __init__(self, name, grammar): + super().__init__(name, grammar) + + @property + def IsTerminal(self): + return True + + @property + def IsNonTerminal(self): + return False + + @property + def IsEpsilon(self): + return False + +class EOF(Terminal): + + def __init__(self, Grammar): + super().__init__('$', Grammar) + +class Sentence(object): + + def __init__(self, *args): + self._symbols = tuple(x for x in args if not x.IsEpsilon) + self.hash = hash(self._symbols) + + def __len__(self): + return len(self._symbols) + + def __add__(self, other): + if isinstance(other, Symbol): + return Sentence(*(self._symbols + (other,))) + + if isinstance(other, Sentence): + return Sentence(*(self._symbols + other._symbols)) + + raise TypeError(other) + + def __or__(self, other): + if isinstance(other, Sentence): + return SentenceList(self, other) + + if isinstance(other, Symbol): + return SentenceList(self, Sentence(other)) + + raise TypeError(other) + + def __repr__(self): + return str(self) + + def __str__(self): + return ("%s " * len(self._symbols) % tuple(self._symbols)).strip() + + def __iter__(self): + return iter(self._symbols) + + def __getitem__(self, index): + return self._symbols[index] + + def __eq__(self, other): + return self._symbols == other._symbols + + def __hash__(self): + return self.hash + + @property + def IsEpsilon(self): + return False + +class SentenceList(object): + + def __init__(self, *args): + self._sentences = list(args) + + def Add(self, symbol): + if not symbol and (symbol is None or not symbol.IsEpsilon): + raise ValueError(symbol) + + self._sentences.append(symbol) + + def __iter__(self): + return iter(self._sentences) + + def __or__(self, other): + if isinstance(other, Sentence): + self.Add(other) + return self + + if isinstance(other, Symbol): + return self | Sentence(other) + + +class Epsilon(Terminal, Sentence): + + def __init__(self, grammar): + super().__init__('epsilon', grammar) + self._symbols = [] + + + def __str__(self): + # return "e" + return u'\N{GREEK SMALL LETTER EPSILON}' + + def __repr__(self): + return 'epsilon' + + def __iter__(self): + yield from () + + def __len__(self): + return 0 + + def __add__(self, other): + return other + + def __eq__(self, other): + return isinstance(other, (Epsilon,)) + + def __hash__(self): + return hash("") + + @property + def IsEpsilon(self): + return True + +class Production(object): + + def __init__(self, nonTerminal, sentence): + + self.Left = nonTerminal + self.Right = sentence + + def __str__(self): + return '%s → %s' % (self.Left, self.Right) + + def __repr__(self): + return '%s → %s' % (self.Left, self.Right) + + def __iter__(self): + yield self.Left + yield self.Right + + def __eq__(self, other): + return isinstance(other, Production) and self.Left == other.Left and self.Right == other.Right + + def __hash__(self): + return hash((self.Left, self.Right)) + + @property + def IsEpsilon(self): + return self.Right.IsEpsilon + +class AttributeProduction(Production): + + def __init__(self, nonTerminal, sentence, attributes): + if not isinstance(sentence, Sentence) and isinstance(sentence, Symbol): + sentence = Sentence(sentence) + super(AttributeProduction, self).__init__(nonTerminal, sentence) + + self.attributes = attributes + + def __str__(self): + return '%s := %s' % (self.Left, self.Right) + + def __repr__(self): + return '%s -> %s' % (self.Left, self.Right) + + def __iter__(self): + yield self.Left + yield self.Right + + + @property + def IsEpsilon(self): + return self.Right.IsEpsilon + + # sintetizar en ingles??????, pending aggrement + def syntetice(self): + pass + +class Grammar(): + + def __init__(self): + + self.Productions = [] + self.nonTerminals = [] + self.terminals = [] + self.startSymbol = None + # production type + self.pType = None + self.Epsilon = Epsilon(self) + self.EOF = EOF(self) + + self.symbDict = { '$': self.EOF } + + def NonTerminal(self, name, startSymbol = False): + + name = name.strip() + if not name: + raise Exception("Empty name") + + term = NonTerminal(name,self) + + if startSymbol: + + if self.startSymbol is None: + self.startSymbol = term + self.nonTerminals.insert(0, term) + else: + raise Exception("Cannot define more than one start symbol.") + else: + self.nonTerminals.append(term) + self.symbDict[name] = term + return term + + def NonTerminals(self, names): + + ans = tuple((self.NonTerminal(x) for x in names.strip().split())) + + return ans + + + def Add_Production(self, production): + + if len(self.Productions) == 0: + self.pType = type(production) + + assert type(production) == self.pType, "The Productions most be of only 1 type." + + # for avoid repeated productions + if production not in production.Left.productions: + production.Left.productions.append(production) + self.Productions.append(production) + + + def Terminal(self, name): + + name = name.strip() + if not name: + raise Exception("Empty name") + + term = Terminal(name, self) + self.terminals.append(term) + self.symbDict[name] = term + return term + + def Terminals(self, names): + + ans = tuple((self.Terminal(x) for x in names.strip().split())) + + return ans + + + def __str__(self): + + # mul = '%s, ' + + ans = 'Non-Terminals:\n\t' + + # nonterminals = mul * (len(self.nonTerminals)-1) + '%s\n' + nonterminals = ', '.join(['%s'] * len(self.nonTerminals)) + '\n' + + ans += nonterminals % tuple(self.nonTerminals) + + ans += 'Terminals:\n\t' + + # terminals = mul * (len(self.terminals)-1) + '%s\n' + terminals = ', '.join(['%s'] * len(self.terminals)) + '\n' + + ans += terminals % tuple(self.terminals) + + ans += 'Productions:\n\t' + + ans += str(self.Productions) + + return ans + + def __getitem__(self, name): + try: + return self.symbDict[name] + except KeyError: + return None + + @property + def to_json(self): + + productions = [] + + for p in self.Productions: + head = p.Left.Name + + body = [] + + for s in p.Right: + body.append(s.Name) + + productions.append({'Head':head, 'Body':body}) + + d={'NonTerminals':[symb.Name for symb in self.nonTerminals], 'Terminals': [symb.Name for symb in self.terminals],\ + 'Productions':productions} + + # [{'Head':p.Left.Name, "Body": [s.Name for s in p.Right]} for p in self.Productions] + return json.dumps(d) + + @staticmethod + def from_json(data): + data = json.loads(data) + + G = Grammar() + dic = {'epsilon':G.Epsilon} + + for term in data['Terminals']: + dic[term] = G.Terminal(term) + + for i, noTerm in enumerate(data['NonTerminals']): + dic[noTerm] = G.NonTerminal(noTerm, not i) + + for p in data['Productions']: + head = p['Head'] + # dic[head] %= Sentence(*[dic[term] for term in p['Body']]) + dic[head] %= sum((dic[term] for term in p['Body'][1:]), dic[p['Body'][0]]) + + return G + + def copy(self): + G = Grammar() + G.Productions = self.Productions.copy() + G.nonTerminals = self.nonTerminals.copy() + G.terminals = self.terminals.copy() + G.pType = self.pType + G.startSymbol = self.startSymbol + G.Epsilon = self.Epsilon + G.EOF = self.EOF + G.symbDict = self.symbDict.copy() + + return G + + @property + def IsAugmentedGrammar(self): + augmented = 0 + for left, right in self.Productions: + if self.startSymbol == left: + augmented += 1 + if augmented <= 1: + return True + else: + return False + + def AugmentedGrammar(self, force=False): + if not self.IsAugmentedGrammar or force: + + G = self.copy() + # S, self.startSymbol, SS = self.startSymbol, None, self.NonTerminal('S\'', True) + S = G.startSymbol + G.startSymbol = None + SS = G.NonTerminal('S\'', True) + if G.pType is AttributeProduction: + SS %= S + G.Epsilon, lambda x : x + else: + SS %= S + G.Epsilon + + return G + else: + return self.copy() + #endchange + +class Item: + + def __init__(self, production, pos, lookaheads=[]): + self.production = production + self.pos = pos + self.lookaheads = frozenset(look for look in lookaheads) + + def __str__(self): + s = str(self.production.Left) + " -> " + if len(self.production.Right) > 0: + for i,c in enumerate(self.production.Right): + if i == self.pos: + s += "." + s += str(self.production.Right[i]) + if self.pos == len(self.production.Right): + s += "." + else: + s += "." + s += ", " + str(self.lookaheads)[10:-1] + return s + + def __repr__(self): + return str(self) + + + def __eq__(self, other): + return ( + (self.pos == other.pos) and + (self.production == other.production) and + (set(self.lookaheads) == set(other.lookaheads)) + ) + + def __hash__(self): + return hash((self.production,self.pos,self.lookaheads)) + + @property + def IsReduceItem(self): + return len(self.production.Right) == self.pos + + @property + def NextSymbol(self): + if self.pos < len(self.production.Right): + return self.production.Right[self.pos] + else: + return None + + def NextItem(self): + if self.pos < len(self.production.Right): + return Item(self.production,self.pos+1,self.lookaheads) + else: + return None + + def Preview(self, skip=1): + unseen = self.production.Right[self.pos+skip:] + return [ unseen + (lookahead,) for lookahead in self.lookaheads ] + + def Center(self): + return Item(self.production, self.pos) \ No newline at end of file diff --git a/src/engine/cp/semantic.py b/src/engine/cp/semantic.py new file mode 100644 index 00000000..97832cc5 --- /dev/null +++ b/src/engine/cp/semantic.py @@ -0,0 +1,379 @@ +import itertools as itt + + +class SemanticError(Exception): + @property + def text(self): + return self.args[0] + + +class Attribute: + def __init__(self, name, typex): + self.name = name + self.type = typex + + def __str__(self): + return f'[attrib] {self.name}: {self.type.name};' + + def __repr__(self): + return str(self) + + +class Method: + def __init__(self, name, param_names, params_types, return_type): + self.name = name + self.param_names = param_names + self.param_types = params_types + self.param_infos = [VariableInfo( + f'_{name}_{pname}', ptype) for pname, ptype in zip(param_names, params_types)] + self.return_type = return_type + self.return_info = VariableInfo(f'_{name}', return_type) + + def __str__(self): + params = ', '.join(f'{n}: {t.name}' for n, t in zip( + self.param_names, self.param_types)) + return f'[method] {self.name}({params}): {self.return_type.name};' + + def __eq__(self, other): + return other.name == self.name and \ + other.return_type == self.return_type and \ + other.param_types == self.param_types + + +class Type: + def __init__(self, name: str, sealed=False, built_in=False): + self.name = name + self.attributes = [] + self.methods = {} + self.parent = None + self.sealed = sealed + self.built_in = built_in + + def set_parent(self, parent): + if self.parent is not None: + raise SemanticError(f'Parent type is already set for {self.name}.') + if parent.sealed: + raise SemanticError( + f'Parent type "{parent.name}" is sealed. Can\'t inherit from it.') + self.parent = parent + + def type_union(self, other): + if self == other: + return other + + t1 = [self] + while t1[-1] != None: + t1.append(t1[-1].parent) + + t2 = [other] + while t2[-1] != None: + t2.append(t2[-1].parent) + + while t1[-2] == t2[-2]: + t1.pop() + t2.pop() + if len(t1) < 2 or len(t2) < 2: + break + + return t1[-1] + + def get_attribute(self, name: str): + try: + return next(attr for attr in self.attributes if attr.name == name) + except StopIteration: + if self.parent is None: + raise SemanticError( + f'Attribute "{name}" is not defined in {self.name}.') + try: + return self.parent.get_attribute(name) + except SemanticError: + raise SemanticError( + f'Attribute "{name}" is not defined in {self.name}.') + + def define_attribute(self, name: str, typex): + try: + self.get_attribute(name) + except SemanticError: + attribute = Attribute(name, typex) + self.attributes.append(attribute) + return attribute + else: + raise SemanticError( + f'Attribute "{name}" is already defined in {self.name}.') + + def get_method(self, name: str): + try: + return self.methods[name] + except KeyError: + if self.parent is None: + raise SemanticError( + f'Method "{name}" is not defined in {self.name}.') + try: + return self.parent.get_method(name) + except SemanticError: + raise SemanticError( + f'Method "{name}" is not defined in {self.name}.') + + def define_method(self, name: str, param_names: list, param_types: list, return_type): + if name in self.methods: + raise SemanticError( + f'Method "{name}" already defined in {self.name}') + # raise SemanticError(f'Method "{name}" already defined in {self.name} with a different signature.') + + method = self.methods[name] = Method( + name, param_names, param_types, return_type) + return method + + def all_attributes(self): + if self.parent: + for attr in self.parent.all_attributes(): + yield attr + for attr in self.attributes: + yield attr + + def all_methods(self): + done = set() + if self.parent: + for method, typex in self.parent.all_methods(): + if method.name in self.methods: + done.add(method.name) + yield (self.methods[method.name], self) + else: + yield (method, typex) + for method in self.methods.values(): + if method.name in done: + continue + yield (method, self) + + def conforms_to(self, other): + return other.bypass() or self == other or self.parent is not None and self.parent.conforms_to(other) + + def bypass(self): + return False + + def __str__(self): + output = f'type {self.name}' + parent = '' if self.parent is None else f' : {self.parent.name}' + output += parent + output += ' {' + output += '\n\t' if self.attributes or self.methods else '' + output += '\n\t'.join(str(x) for x in self.attributes) + output += '\n\t' if self.attributes else '' + output += '\n\t'.join(str(x) for x in self.methods.values()) + output += '\n' if self.methods else '' + output += '}\n' + return output + + def __repr__(self): + return str(self) + + +class SelfType(Type): + def __init__(self): + Type.__init__(self, 'SELF_TYPE') + self.sealed = True + + def conforms_to(self, other): + return False + + def bypass(self): + return True + + def __eq__(self, other): + return isinstance(other, SelfType) + + +class ErrorType(Type): + def __init__(self, message=""): + Type.__init__(self, '') + self.sealed = True + self.message = message + + def union_type(self, other): + return self + + def conforms_to(self, other): + return True + + def bypass(self): + return True + + def __eq__(self, other): + return isinstance(other, Type) + + +class Context: + def __init__(self): + self.inheritance = {} + self.types = {} + self.basic_types = ['Object', 'IO', 'Int', 'String', 'Bool'] + + def create_type(self, name: str, builtin=False): + if name in self.basic_types and name in self.types: + raise SemanticError( + f'SemanticError: Redefinition of basic class {name}.') + if name in self.types: + raise SemanticError( + f'Type with the same name ({name}) already in context.') + typex = self.types[name] = Type(name, built_in=builtin) + return typex + + def add_type(self, typex): + if typex.name in self.basic_types: + raise SemanticError( + f'SemanticError: Redefinition of basic class {typex.name}.') + if typex.name in self.types: + raise SemanticError( + f'Type with the same name ({typex.name}) already in context.') + self.types[typex.name] = typex + return typex + + def get_type(self, name: str): + try: + return self.types[name] + except KeyError: + raise SemanticError(f'Type "{name}" is not defined.') + + def inheritance_deep(self, type_name: str) -> int: + if type_name is None: + return -1 + if type_name in ('IO', 'Int', 'String', 'Bool', 'Object'): + return 0 + return 1 + self.inheritance_deep(self.inheritance[type_name]) + + def __str__(self): + return '{\n\t' + '\n\t'.join(y for x in self.types.values() for y in str(x).split('\n')) + '\n}' + + def __repr__(self): + return str(self) + + +class VariableInfo: + def __init__(self, name, vtype): + self.real_name = name + self.name = name + self.type = vtype + self.calls = [] + self.assigns = [] + self.infered = False + + def set_calls(self, typex): + self.calls.append(typex) + + def set_assigns(self, typex): + if not self.infered: + self.assigns.append(typex) + + def infer_type(self): + if not self.infered: + message = "" + t = all(not x.built_in for x in self.calls + self.assigns) + # print(t) + if t: + call = None + for typex in self.calls: + if not call or typex.conforms_to(call): + call = typex + elif call.conforms_to(typex): + pass + else: + call = ErrorType() + break + + assign = None + for typex in self.assigns: + assign = typex if not assign else assign.type_union(typex) + + if assign: + self.type = assign if not call or assign.conforms_to( + call) else ErrorType() + else: + self.type = call + + self.calls = [] + self.assigns = [] + + return self.infered, message + + else: + self.type = None + for x in self.assigns + self.calls: + if x.built_in: + self.type = x + break + error = [] + + # print(self.type.name) + + for x in self.assigns + self.calls: + if not x.conforms_to(self.type): + error.append(x) + + message = f"Incompatible Types {self.type.name} and " + \ + " ".join(e.name for e in error) if error else "" + + self.infered = True + + self.calls = [] + self.assigns = [] + + return True, message + + return False, "" + + def __repr__(self): + return str(self) + + def __str__(self): + return f'Variable Name: {self.name}, Variable Type: {self.type} \n' + + +class Scope: + def __init__(self, parent=None): + self.locals = [] + self.parent = parent + self.children = [] + self.index = 0 if parent is None else len(parent) + + def __len__(self): + return len(self.locals) + + def create_child(self): + child = Scope(self) + self.children.append(child) + return child + + def define_variable(self, vname, vtype, let=False): + info = VariableInfo(vname, vtype) + for i in range(len(self.locals)): + if self.locals[i].name == vname: + if not let: + raise SemanticError( + f'Variable {vname} already exists in the current context') + else: + self.locals[i] = info + break + else: + self.locals.append(info) + return info + + def find_variable(self, vname, index=None): + locals = self.locals if index is None else itt.islice( + self.locals, index) + try: + return next(x for x in locals if x.name == vname) + except StopIteration: + return self.parent.find_variable(vname, self.index) if self.parent is not None else None + + def is_defined(self, vname): + return self.find_variable(vname) is not None + + def is_local(self, vname): + return any(True for x in self.locals if x.name == vname) + + def __repr__(self): + return str(self) + + def __str__(self): + return "".join(str(i) for i in self.locals) + "".join(str(s) for s in self.children) + # return f'Scope: {self.index}\n' + "\n".join(str(x) for x in self.locals) + "\n".join(str(s) for s in self.children) diff --git a/src/engine/cp/utils.py b/src/engine/cp/utils.py new file mode 100644 index 00000000..35fd38de --- /dev/null +++ b/src/engine/cp/utils.py @@ -0,0 +1,104 @@ +class ContainerSet: + def __init__(self, *values, contains_epsilon=False): + self.set = set(values) + self.contains_epsilon = contains_epsilon + + def add(self, value): + n = len(self.set) + self.set.add(value) + return n != len(self.set) + + def extend(self, values): + change = False + for value in values: + change |= self.add(value) + return change + + def set_epsilon(self, value=True): + last = self.contains_epsilon + self.contains_epsilon = value + return last != self.contains_epsilon + + def update(self, other): + n = len(self.set) + self.set.update(other.set) + return n != len(self.set) + + def epsilon_update(self, other): + return self.set_epsilon(self.contains_epsilon | other.contains_epsilon) + + def hard_update(self, other): + return self.update(other) | self.epsilon_update(other) + + def find_match(self, match): + for item in self.set: + if item == match: + return item + return None + + def items(self): + return self.set.union({u'\N{GREEK SMALL LETTER EPSILON}'} if self.contains_epsilon else {}) + + def __len__(self): + return len(self.set) + int(self.contains_epsilon) + + def __str__(self): + return '%s-%s' % (str(self.set), self.contains_epsilon) + + def __repr__(self): + return str(self) + + def __iter__(self): + return iter(self.set) + + def __nonzero__(self): + return len(self) > 0 + + def __eq__(self, other): + if isinstance(other, set): + return self.set == other + return isinstance(other, ContainerSet) and self.set == other.set and self.contains_epsilon == other.contains_epsilon + +class Token: + """ + Basic token class. + + Parameters + ---------- + lex : str + Token's lexeme. + token_type : Enum + Token's type. + """ + + def __init__(self, lex, token_type, line=0, column=0): + self.lex = lex + self.token_type = token_type + self.line = line + self.column = column + + @property + def type(self): + return self.token_type + + @property + def value(self): + return self.lex + + @property + def lineno(self): + return self.line + + @property + def lexpos(self): + return self.column + + def __str__(self): + return f'{self.token_type}: {self.lex}' + + def __repr__(self): + return str(self) + + @property + def is_valid(self): + return True diff --git a/src/engine/cp/visitor.py b/src/engine/cp/visitor.py new file mode 100644 index 00000000..500298bc --- /dev/null +++ b/src/engine/cp/visitor.py @@ -0,0 +1,80 @@ +# The MIT License (MIT) +# +# Copyright (c) 2013 Curtis Schlak +# +# 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. + +import inspect + +__all__ = ['on', 'when'] + +def on(param_name): + def f(fn): + dispatcher = Dispatcher(param_name, fn) + return dispatcher + return f + + +def when(param_type): + def f(fn): + frame = inspect.currentframe().f_back + func_name = fn.func_name if 'func_name' in dir(fn) else fn.__name__ + dispatcher = frame.f_locals[func_name] + if not isinstance(dispatcher, Dispatcher): + dispatcher = dispatcher.dispatcher + dispatcher.add_target(param_type, fn) + def ff(*args, **kw): + return dispatcher(*args, **kw) + ff.dispatcher = dispatcher + return ff + return f + + +class Dispatcher(object): + def __init__(self, param_name, fn): + frame = inspect.currentframe().f_back.f_back + top_level = frame.f_locals == frame.f_globals + self.param_index = self.__argspec(fn).args.index(param_name) + self.param_name = param_name + self.targets = {} + + def __call__(self, *args, **kw): + typ = args[self.param_index].__class__ + d = self.targets.get(typ) + if d is not None: + return d(*args, **kw) + else: + issub = issubclass + t = self.targets + ks = t.keys() + ans = [t[k](*args, **kw) for k in ks if issub(typ, k)] + if len(ans) == 1: + return ans.pop() + return ans + + def add_target(self, typ, target): + self.targets[typ] = target + + @staticmethod + def __argspec(fn): + # Support for Python 3 type hints requires inspect.getfullargspec + if hasattr(inspect, 'getfullargspec'): + return inspect.getfullargspec(fn) + else: + return inspect.getargspec(fn) diff --git a/src/engine/errors.py b/src/engine/errors.py new file mode 100644 index 00000000..4f875ca9 --- /dev/null +++ b/src/engine/errors.py @@ -0,0 +1,8 @@ +# Generic Error +ERROR = '(%d, %d) - %s: %s' + +def LexicographicError(line, col, message): + return ERROR % (line, col, "LexicographicError", message) + +def SyntacticError(line, col, message): + return ERROR % (line, col, "SyntacticError", message) \ No newline at end of file diff --git a/src/engine/lexer.py b/src/engine/lexer.py new file mode 100644 index 00000000..6036ffb8 --- /dev/null +++ b/src/engine/lexer.py @@ -0,0 +1,289 @@ +import ply.lex as lex +from .errors import LexicographicError +from .cp import Token, Grammar + +def find_column(lexer, token): + line_start = lexer.lexdata.rfind('\n', 0, token.lexpos) + return token.lexpos - line_start + + +class CoolLexer: + def __init__(self): + self.CoolGrammar = None + self.build() + self.last_token = None # dont touch + + ####### Tokens ####### + + keywords = [ + 'CLASS', + 'ELSE', + # false case is independently treated + 'FI', + 'IF', + 'IN', + 'INHERITS', + 'ISVOID', + 'LET', + 'LOOP', + 'POOL', + 'THEN', + 'WHILE', + 'CASE', + 'ESAC', + 'NEW', + 'OF', + 'NOT' + # true case is independently treated + ] + + literals = ['+', '-', '*', '/', ':', ';', + '(', ')', '{', '}', '@', '.', ','] + + tokens = [ + # Identifiers + 'TYPE', 'ID', + # Primitive data types + 'INTEGER', 'STRING', 'BOOL', + # Special keywords + 'ACTION', + # Operators + 'ASSIGN', 'LESS', 'LESSEQUAL', 'EQUAL', 'INT_COMPLEMENT', + 'OPAR','CPAR','OCURL','CCURL','COLON','COMMA', + 'DOT', 'SEMI', 'AT','STAR','DIV','PLUS','MINUS' + ] + list(keywords) + + t_ASSIGN = r'\<\-' # <- + t_LESS = r'\<' # < + t_LESSEQUAL = r'\<\=' # <= + t_EQUAL = r'\=' # = + t_INT_COMPLEMENT = r'\~' # ~ + t_ACTION = r'\=\>' # => + + t_OPAR = r'\(' # ( + t_CPAR = r'\)' # ) + t_OCURL = r'\{' # { + t_CCURL = r'\}' # } + t_COLON = r'\:' # : + t_COMMA = r'\,' # , + t_DOT = r'\.' # . + t_SEMI = r'\;' # ; + t_AT = r'\@' # @ + t_STAR = r'\*' # * + t_DIV = r'\/' # / + t_PLUS = r'\+' # + + t_MINUS = r'\-' # - + + ####### Extra Methods ####### + + def iskeyword(self, t): + d = t.value.upper() + if d in self.keywords: + t.type = d + + def addline(self, t): + t.lexer.lineno += len(t.value) + + def find_position(self, input, token): + line_start = input.rfind('\n', 0, token.lexpos) + 1 + return (token.lineno, (token.lexpos - line_start) + 1) + + def lexer_error(self, t, message): + self.lexer.errors.append(LexicographicError( + *self.find_position(t.lexer.lexdata, t), message)) + + ##### TOKEN RULES ##### + + t_ignore = ' \t\f\r\v' + t_ignore_single_comment = r'\-\-[^\n]*' + + # count line number + def t_INITIAL_comment_newline(self, t): + r'\n+' + self.addline(t) + + def t_BOOL(self, t): + r't[rR][uU][eE]|f[aA][lL][sS][eE]' + d = t.value.lower() + t.value = True if d == 'true' else False + return t + + def t_INTEGER(self, t): + r'[0-9]+' + t.value = int(t.value) + return t + + def t_TYPE(self, t): + r'[A-Z][A-Za-z0-9_]*' + self.iskeyword(t) + return t + + def t_ID(self, t): + r'[a-z][A-Za-z0-9_]*' + self.iskeyword(t) + return t + + def t_error(self, t): + self.lexer_error(t, f'ERROR "{t.value}"') + t.lexer.skip(1) + + + states = ( + ('string', 'exclusive'), + ('comment', 'exclusive') + ) + + def t_comment(self, t): + r'\(\*' + t.lexer.comments = 1 + #t.lexer.unterminated_slash = False + t.lexer.begin('comment') + + t_comment_ignore = '' + + def t_comment_opar(self, t): + r'\(\*' + t.lexer.comments += 1 + + def t_comment_cpar(self, t): + r'\*\)' + t.lexer.comments -= 1 + if not t.lexer.comments: + t.lexer.begin('INITIAL') + + def t_comment_eof(self, t): + self.lexer_error(t, 'EOF in comment') + + def t_comment_error(self, t): + #print(t.value, 'error en comment') + t.lexer.skip(1) + + def t_comment_literals(self, t): + r'\+|\-|\*|\:|\;|\(|\)|\{|\}|\@|\.|\,|\/|\<|\<\-|\<\=|\=|\~|\=|>' + + # string state + def t_string(self, t): + r'\"' + t.lexer.begin('string') + t.lexer.string = '' + + t_string_ignore = '' + + def t_string_error(self, t): + #print(t.value, 'error en string ') + t.lexer.skip(1) + + def t_string_end(self, t): + r'\"' + if not t.lexer.unterminated_slash: + t.value = t.lexer.string + t.type = 'STRING' + t.lexer.begin('INITIAL') + t.lexer.string = '' + return t + else: + t.lexer.string += '"' + t.lexer.unterminated_slash = False + + def t_string_newline(self, t): + r'\n' + t.lexer.lineno += 1 + if not t.lexer.unterminated_slash: + self.lexer_error(t, 'Unterminated string constant') + else: + t.lexer.unterminated_slash = False + t.lexer.string += '\n' + + def t_string_null(self, t): + r'\0' + self.lexer_error(t, 'String contains null character') + + def t_string_slash(self, t): + r'\\' + if t.lexer.unterminated_slash: + t.lexer.string += '\\' + t.lexer.unterminated_slash = False + else: + t.lexer.unterminated_slash = True + + def t_string_eof(self, t): + self.lexer_error(t, 'EOF in string constant') + + def t_string_all(self, t): + r'[^\n]' + if t.lexer.unterminated_slash: + spec = {'b': '\b', 't': '\t', 'f': '\f', 'n': '\n', '\\':'\\'} + if t.value in ['b', 't', 'f', 'n', '\\']: + t.lexer.string += spec[t.value] + else: + t.lexer.string += t.value + t.lexer.unterminated_slash = False + else: + t.lexer.string += t.value + + def build(self): + self.lexer = lex.lex(debug=0, module=self) + self.lexer.errors = [] + self.lexer.unterminated_slash = False + self.lexer.string = '' + + ###### CoolGrammar ###### + CoolGrammar = Grammar() + # terminals + CoolGrammar.Terminals('class inherits') + CoolGrammar.Terminals('if then else fi') + CoolGrammar.Terminals('while loop pool') + CoolGrammar.Terminals('let in') + CoolGrammar.Terminals('case of esac') + CoolGrammar.Terminals('; : , . @ ( ) { } assign action') + CoolGrammar.Terminals('+ - * / isvoid int_complement') + CoolGrammar.Terminals('not less lessequal equal') + CoolGrammar.Terminals('new id type integer string bool') + + self.CoolGrammar = CoolGrammar + tokens_dict = dict() + + for tok in self.tokens + self.literals: + if tok not in tokens_dict: + tokens_dict[tok] = CoolGrammar[tok.lower()] + + ###### TOKENIZER ###### + + def token(self): + if not (self.last_token is None) and self.last_token.token_type==self.CoolGrammar.EOF: + return None + token = self.lexer.token() + if token is None: + self.last_token = Token('$', self.CoolGrammar.EOF) + return None + else: + self.last_token = Token(token.value, token.type, *self.find_position(self.lexer.lexdata, token)) + return self.last_token + + def reset(self): + self.last_token = None + + def tokenize(self, code): + tokens = [] + self.lexer.input(code) + while True: + token = self.token() + if token is None: + break + tokens.append(token) + + # tokens.append(Token('$', self.CoolGrammar.EOF)) + + return tokens, self.lexer.errors + + def __iter__(self): + return self + + def __next__(self): + t = self.token() + if t is None: + raise StopIteration + return t + + def next(self): + return self.__next__() diff --git a/src/engine/parser/__init__.py b/src/engine/parser/__init__.py new file mode 100644 index 00000000..b4de894d --- /dev/null +++ b/src/engine/parser/__init__.py @@ -0,0 +1,2 @@ +from .cool_parser import CoolParser +from .ast_parser import * diff --git a/src/engine/parser/ast_parser.py b/src/engine/parser/ast_parser.py new file mode 100644 index 00000000..8c10a6eb --- /dev/null +++ b/src/engine/parser/ast_parser.py @@ -0,0 +1,245 @@ +from engine.cp.utils import Token +# AST Classes + + +class Node: + def __init__(self): + self.line = 0 + self.column = 0 + + +class ErrorNode(Node): + pass + + +class ProgramNode(Node): + def __init__(self, declarations): + self.declarations = declarations + self.line = declarations[0].line + self.column = declarations[0].column + + +class DeclarationNode(Node): + pass + + +class LetVariableDeclaration(DeclarationNode): + def __init__(self, idx, typex, expression=None): + self.id = idx + self.type = typex + self.expression = expression + self.line = self.id.line + self.column = self.id.column + + def __iter__(self): + yield from (self.id, self.type, self.expression) + + +class CaseActionExpression(DeclarationNode): + def __init__(self, idx, typex, expression=Node): + self.id = idx + self.type = Token(typex, 'ID') if isinstance(typex, str) else typex + self.expression = expression + self.line = self.id.line + self.column = self.id.column + + def __iter__(self): + yield from (self.id, self.type, self.expression) + + +class ClassDeclarationNode(DeclarationNode): + def __init__(self, idx, features, parent=None): + self.id = idx + self.parent = parent + self.features = features + self.line = idx.line + self.column = idx.column + + +class AttrDeclarationNode(DeclarationNode): + def __init__(self, idx, typex=None, expression=None): + self.id = Token(idx, 'ID', 0, 0) if isinstance(idx, str) else idx + self.type = typex + self.expression = expression + self.line = self.id.line + self.column = self.id.column + + def __iter__(self): + yield from (self.id, self.type, self.expression) + + +class FuncDeclarationNode(DeclarationNode): + def __init__(self, idx, params, return_type, body): + self.id = idx + self.params = params + self.type = return_type + self.body = body + self.line = idx.line + self.column = idx.column + + +class ExpressionNode(Node): + pass + + +class IfThenElseNode(ExpressionNode): + def __init__(self, condition, if_body, else_body): + self.condition = condition + self.if_body = if_body + self.else_body = else_body + self.line = condition.line + self.column = condition.column + + +class WhileLoopNode(ExpressionNode): + def __init__(self, condition, body): + self.condition = condition + self.body = body + self.line = condition.line + self.column = condition.column + + +class BlockNode(ExpressionNode): + def __init__(self, expressions): + self.expressions = expressions + self.line = expressions[-1].line + self.column = expressions[-1].column + + +class LetInNode(ExpressionNode): + def __init__(self, let_body, in_body=None): + self.let_body = let_body # [LetVariableDeclarations] + self.in_body = in_body + if in_body is None: + last = self.let_body[-1] + self.line = last.line + self.column = last.column + else: + self.line = in_body.line + self.column = in_body.column + + +class CaseOfNode(ExpressionNode): + def __init__(self, expression, branches): + self.expression = expression + self.branches = branches + self.line = expression.line + self.column = expression.column + + +class AssignNode(ExpressionNode): + def __init__(self, idx, expression): + self.id = idx + self.expression = expression + self.line = idx.line + self.column = idx.column + + +class UnaryNode(ExpressionNode): + def __init__(self, expression): + self.expression = expression + self.line = expression.line + self.column = expression.column + + +class NotNode(UnaryNode): + pass + + +class BinaryNode(ExpressionNode): + def __init__(self, left, right): + self.left = left + self.right = right + self.line = left.line + self.column = left.column + + +class LessEqualNode(BinaryNode): + pass + + +class LessNode(BinaryNode): + pass + + +class EqualNode(BinaryNode): + pass + + +class ArithmeticNode(BinaryNode): + pass + + +class PlusNode(ArithmeticNode): + pass + + +class MinusNode(ArithmeticNode): + pass + + +class StarNode(ArithmeticNode): + pass + + +class DivNode(ArithmeticNode): + pass + + +class IsVoidNode(UnaryNode): + pass + + +class ComplementNode(UnaryNode): + pass + + +class FunctionCallNode(ExpressionNode): + def __init__(self, obj, idx, args, typex=None): + self.obj = obj + self.id = idx + self.args = args + self.type = typex + self.line = idx.line + self.column = idx.column + + def __iter__(self): + yield from (self.id, self.type, self.expression) + + +class MemberCallNode(ExpressionNode): + def __init__(self, idx, args): + self.id = idx + self.args = args + self.line = idx.line + self.column = idx.column + + +class NewNode(ExpressionNode): + def __init__(self, typex): + self.type = typex + self.line = typex.line + self.column = typex.column + + +class AtomicNode(ExpressionNode): + def __init__(self, token): + self.token = token + self.line = token.line + self.column = token.column + + +class IntegerNode(AtomicNode): + pass + + +class IdNode(AtomicNode): + pass + + +class StringNode(AtomicNode): + pass + + +class BoolNode(AtomicNode): + pass diff --git a/src/engine/parser/cool_parser.py b/src/engine/parser/cool_parser.py new file mode 100644 index 00000000..15a22ffb --- /dev/null +++ b/src/engine/parser/cool_parser.py @@ -0,0 +1,467 @@ +from ply import yacc +from ..lexer import CoolLexer, find_column +from .ast_parser import * +from ..commons import terminals, keywords, tokens +from ..errors import SyntacticError +# Parser + + +class CoolParser: + """ + CoolParser class. + """ + + def __init__(self, lexer): + self.tokens = tokens + tuple(terminals.values()) + self.parser = yacc.yacc(module=self, start='program') + self.error_list = [] + self.lexer = lexer + + def parse(self, code): + result = self.parser.parse( + code, self.lexer.lexer, tokenfunc=self.lexer.token) + return result, self.error_list + + precedence = ( + ('right', 'ASSIGN'), + ('right', 'NOT'), + ('nonassoc', 'LESS', 'LESSEQUAL', 'EQUAL'), + ('left', 'PLUS', 'MINUS'), + ('left', 'STAR', 'DIV'), + ('right', 'ISVOID'), + ('right', 'INT_COMPLEMENT'), + ('left', 'AT'), + ('left', 'DOT'), + ) + + def p_epsilon(self, p): + 'epsilon :' + pass + + def p_program(self, p): + '''program : class_list''' + p[0] = ProgramNode(p[1]) + + def p_class_list(self, p): + '''class_list : def_class class_list + | def_class''' + if len(p) == 3: + p[0] = [p[1]] + p[2] + else: + p[0] = [p[1]] + + def p_class_list_error(self, p): + '''class_list : error class_list ''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = [p[1]] + p[2] + + def p_def_class(self, p): + '''def_class : CLASS TYPE OCURL feature_list CCURL SEMI + | CLASS TYPE INHERITS TYPE OCURL feature_list CCURL SEMI ''' + if len(p) == 7: + p[0] = ClassDeclarationNode(p.slice[2], p[4]) + else: + p[0] = ClassDeclarationNode( + p.slice[2], p[6], parent=p.slice[4]) + + def p_def_class_error(self, p): + '''def_class : CLASS error OCURL feature_list CCURL SEMI + | CLASS TYPE OCURL error CCURL SEMI + | CLASS error OCURL error CCURL SEMI + | CLASS TYPE INHERITS TYPE OCURL error CCURL SEMI + | CLASS TYPE INHERITS error OCURL error CCURL SEMI + | CLASS error INHERITS TYPE OCURL error CCURL SEMI + | CLASS error INHERITS error OCURL feature_list CCURL SEMI + | CLASS error INHERITS error OCURL error CCURL SEMI ''' + p[0] = ErrorNode() + + def p_feature_list(self, p): + '''feature_list : feature feature_list + | epsilon''' + if len(p) == 3: + p[0] = [p[1]] + p[2] + else: + p[0] = [] + + def p_feature_list_error(self, p): + 'feature_list : error feature_list' + p[0] = [p[1]] + p[2] + + def p_feature_attribute(self, p): + '''feature : ID COLON TYPE SEMI + | ID COLON TYPE ASSIGN expr SEMI ''' + if len(p) == 5: + p[0] = AttrDeclarationNode(p.slice[1], p.slice[3]) + else: + p[0] = AttrDeclarationNode( + p.slice[1], p.slice[3], p[5]) + + def p_def_attribute_error(self, p): + '''feature : error COLON TYPE + | ID COLON error + | error COLON error + | error COLON TYPE ASSIGN expr + | ID COLON error ASSIGN expr + | ID COLON TYPE ASSIGN error + | ID COLON error ASSIGN error + | error COLON TYPE ASSIGN error + | error COLON error ASSIGN expr + | error COLON error ASSIGN error''' + p[0] = ErrorNode() + + def p_feature_function(self, p): + '''feature : ID OPAR param_list CPAR COLON TYPE OCURL expr CCURL SEMI + | ID OPAR CPAR COLON TYPE OCURL expr CCURL SEMI ''' + if len(p) == 11: + p[0] = FuncDeclarationNode( + p.slice[1], p[3], p.slice[6], p[8]) + else: + p[0] = FuncDeclarationNode( + p.slice[1], [], p.slice[5], p[7]) + + def p_feature_function_error(self, p): + '''feature : error OPAR param_list CPAR COLON TYPE OCURL expr CCURL SEMI + | ID OPAR error CPAR COLON TYPE OCURL expr CCURL SEMI + | ID OPAR param_list CPAR COLON error OCURL expr CCURL SEMI + | ID OPAR param_list CPAR COLON TYPE OCURL error CCURL SEMI + | error OPAR error CPAR COLON TYPE OCURL expr CCURL SEMI + | error OPAR param_list CPAR COLON error OCURL expr CCURL SEMI + | error OPAR param_list CPAR COLON TYPE OCURL error CCURL SEMI + | ID OPAR error CPAR COLON error OCURL error CCURL SEMI + | error OPAR error CPAR COLON TYPE OCURL error CCURL SEMI + | error OPAR error CPAR COLON error OCURL error CCURL SEMI + | error OPAR param_list CPAR COLON error OCURL error CCURL SEMI + | error OPAR CPAR COLON TYPE OCURL expr CCURL SEMI + | ID OPAR CPAR COLON error OCURL expr CCURL SEMI + | ID OPAR CPAR COLON TYPE OCURL error CCURL SEMI + | ID OPAR CPAR COLON error OCURL error CCURL SEMI + | ID error CPAR COLON TYPE OCURL error CCURL SEMI + | ID error CPAR COLON TYPE OCURL expr CCURL SEMI + | ID error CPAR COLON error OCURL error CCURL SEMI ''' + p[0] = ErrorNode() + + def p_param_list(self, p): + '''param_list : param + | param COMMA param_list''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = [p[1]] + p[3] + + def p_param(self, p): + '''param : ID COLON TYPE''' + p[0] = (p.slice[1], p.slice[3]) + + def p_expr_block(self, p): + '''expr_block : expr SEMI + | expr SEMI expr_block''' + if len(p) == 3: + p[0] = [p[1]] + else: + p[0] = [p[1]] + p[3] + + def p_let_list(self, p): + '''let_list : ID COLON TYPE + | ID COLON TYPE ASSIGN expr + | ID COLON TYPE COMMA let_list + | ID COLON TYPE ASSIGN expr COMMA let_list''' + if len(p) == 4: + p[0] = [LetVariableDeclaration(p.slice[1], p.slice[3], None)] + elif len(p) == 6 and p.slice[4].lex == '<-': + p[0] = [LetVariableDeclaration( + p.slice[1], p.slice[3], p[5])] + elif len(p) == 6: + p[0] = [LetVariableDeclaration( + p.slice[1], p.slice[3], None)] + p[5] + else: + p[0] = [LetVariableDeclaration( + p.slice[1], p.slice[3], p[5])] + p[7] + + def p_let_list_error(self, p): + '''let_list : error COLON TYPE + | ID COLON error + | error COLON error + | error COLON TYPE ASSIGN expr + | ID COLON error ASSIGN expr + | ID COLON TYPE ASSIGN error + | ID COLON error ASSIGN error + | error COLON error ASSIGN expr + | error COLON TYPE ASSIGN error + | error COLON error ASSIGN error + | error COLON TYPE COMMA let_list + | ID COLON error COMMA let_list + | ID COLON TYPE COMMA error + | ID COLON error COMMA error + | error COLON error COMMA let_list + | error COLON TYPE COMMA error + | error COLON error COMMA error + | error COLON error ASSIGN error COMMA error + | ID COLON error ASSIGN error COMMA error + | error COLON TYPE ASSIGN error COMMA error + | ID COLON TYPE ASSIGN error COMMA error + | error COLON error ASSIGN expr COMMA error + | ID COLON error ASSIGN expr COMMA error + | error COLON TYPE ASSIGN expr COMMA error + | ID COLON TYPE ASSIGN expr COMMA error + | error COLON error ASSIGN error COMMA let_list + | ID COLON error ASSIGN error COMMA let_list + | error COLON TYPE ASSIGN error COMMA let_list + | ID COLON TYPE ASSIGN error COMMA let_list + | error COLON error ASSIGN expr COMMA let_list + | ID COLON error ASSIGN expr COMMA let_list + | error COLON TYPE ASSIGN expr COMMA let_list ''' + p[0] = [ErrorNode()] + + def p_case_list(self, p): + '''case_list : ID COLON TYPE ACTION expr SEMI + | ID COLON TYPE ACTION expr SEMI case_list ''' + if len(p) == 7: + p[0] = [CaseActionExpression( + p.slice[1], p.slice[3], p[5])] + else: + p[0] = [CaseActionExpression( + p.slice[1], p.slice[3], p[5])] + p[7] + + def p_case_list_error(self, p): + '''case_list : error COLON TYPE ACTION expr SEMI + | ID COLON error ACTION expr SEMI + | ID COLON TYPE ACTION error SEMI + | ID COLON TYPE error error SEMI + | error COLON error ACTION expr SEMI + | error COLON TYPE ACTION error SEMI + | error COLON error ACTION error SEMI + | error COLON TYPE ACTION expr SEMI case_list + | ID COLON error ACTION expr SEMI case_list + | ID COLON TYPE ACTION error SEMI case_list + | ID COLON TYPE error error SEMI case_list + | error COLON error ACTION expr SEMI case_list + | error COLON TYPE ACTION error SEMI case_list + | error COLON error ACTION error SEMI case_list + | error COLON TYPE ACTION expr SEMI error + | ID COLON TYPE ACTION expr SEMI error + | ID COLON error ACTION expr SEMI error + | ID COLON TYPE error error SEMI error + | error COLON error ACTION expr SEMI error + | error COLON TYPE ACTION error SEMI error + | error COLON error ACTION error SEMI error''' + p[0] = [ErrorNode()] + + def p_func_call(self, p): + '''funccall : ID OPAR CPAR + | ID OPAR arg_list CPAR''' + if len(p) == 4: + p[0] = (p.slice[1], []) + else: + p[0] = (p.slice[1], p[3]) + + def p_func_call_error(self, p): + '''funccall : error OPAR CPAR + | ID OPAR error CPAR + | error OPAR arg_list CPAR + | error OPAR error CPAR''' + p[0] = (ErrorNode(), ErrorNode()) + + def p_arg_list(self, p): + ''' arg_list : expr + | expr COMMA arg_list''' + if len(p) == 2: + p[0] = [p[1]] + else: + p[0] = [p[1]] + p[3] + + def p_arg_list_error(self, p): + ''' arg_list : error + | error COMMA arg_list''' + p[0] = [ErrorNode()] + + def p_expr(self, p): + '''expr : ID ASSIGN expr + | operat ''' + if len(p) == 4: + p[0] = AssignNode(p.slice[1], p[3]) + else: + p[0] = p[1] + + def p_expr_error(self, p): + '''expr : ID ASSIGN error + | error ASSIGN expr ''' + p[0] = ErrorNode() + + def p_comp(self, p): + '''operat : operat LESSEQUAL operat + | operat LESS operat + | operat EQUAL operat''' + if p.slice[2].lex == '<=': + p[0] = LessEqualNode(p[1], p[3]) + elif p.slice[2].lex == '<': + p[0] = LessNode(p[1], p[3]) + else: + p[0] = EqualNode(p[1], p[3]) + + def p_comp_error(self, p): + '''operat : error LESSEQUAL operat + | error LESSEQUAL error + | operat LESSEQUAL error + | error LESS operat + | error LESS error + | operat LESS error + | error EQUAL operat + | error EQUAL error + | operat EQUAL error''' + p[0] = ErrorNode() + + def p_arith(self, p): + '''operat : operat PLUS operat + | operat MINUS operat + | operat STAR operat + | operat DIV operat ''' + if p.slice[2].lex == '+': + p[0] = PlusNode(p[1], p[3]) + elif p.slice[2].lex == '-': + p[0] = MinusNode(p[1], p[3]) + elif p.slice[2].lex == '*': + p[0] = StarNode(p[1], p[3]) + else: + p[0] = DivNode(p[1], p[3]) + + def p_operat_error(self, p): + '''operat : operat PLUS error + | error PLUS error + | error PLUS operat + | error MINUS operat + | error MINUS error + | operat MINUS error + | operat STAR error + | error STAR error + | error STAR operat + | operat DIV error + | error DIV error + | error DIV operat ''' + p[0] = ErrorNode() + + def p_base_operat(self, p): + '''operat : baseop''' + p[0] = p[1] + + def p_static_call(self, p): + '''baseop : subatom AT TYPE DOT funccall ''' + p[0] = FunctionCallNode(p[1], *p[5], p.slice[3]) + + def p_static_call_error(self, p): + '''baseop : error AT TYPE DOT funccall + | subatom AT error DOT funccall + | subatom AT TYPE DOT error + | error AT error DOT funccall + | error AT TYPE DOT error + | subatom AT error DOT error + | error AT error DOT error ''' + p[0] = ErrorNode() + + def p_sub_atom(self, p): + '''baseop : subatom''' + p[0] = p[1] + + def p_parent_expr(self, p): + '''subatom : OPAR expr CPAR''' + p[0] = p[2] + + def p_parent_expr_error(self, p): + '''subatom : error expr CPAR + | OPAR expr error''' + p[0] = ErrorNode() + + def p_dynamic_call(self, p): + '''subatom : subatom DOT funccall ''' + p[0] = FunctionCallNode(p[1], *p[3]) + + def p_dynamic_call_error(self, p): + '''subatom : subatom DOT error + | error DOT funccall + | error DOT error ''' + p[0] = ErrorNode() + + def p_member_call(self, p): + '''subatom : funccall ''' + p[0] = MemberCallNode(*p[1]) + + def p_unary_operations(self, p): + '''subatom : INT_COMPLEMENT baseop + | NOT operat + | ISVOID baseop ''' + if p.slice[1].lex == '~': + p[0] = ComplementNode(p[2]) + elif p.slice[1].lex == 'not': + p[0] = NotNode(p[2]) + else: + p[0] = IsVoidNode(p[2]) + + def p_unary_operations_error(self, p): + '''subatom : NOT error ''' + p[0] = ErrorNode() + + def p_complex_sub_atom(self, p): + '''subatom : IF expr THEN expr ELSE expr FI + | WHILE expr LOOP expr POOL + | LET let_list IN expr + | CASE expr OF case_list ESAC ''' + # | LET let_list + if p.slice[1].lex == 'if': + p[0] = IfThenElseNode(p[2], p[4], p[6]) + elif p.slice[1].lex == 'while': + p[0] = WhileLoopNode(p[2], p[4]) + elif p.slice[1].lex == 'let': + p[0] = LetInNode(p[2], p[4]) + # elif p.slice[1].lex == 'let': + # p[0] = LetInNode(p[2], None) + else: + p[0] = CaseOfNode(p[2], p[4]) + + def p_atom(self, p): + '''subatom : atom''' + p[0] = p[1] + + def p_new(self, p): + '''atom : NEW TYPE''' + p[0] = NewNode(p.slice[2]) + + def p_new_error(self, p): + '''atom : NEW error''' + p[0] = ErrorNode() + + def p_atom_expr_block(self, p): + '''atom : OCURL expr_block CCURL ''' + p[0] = BlockNode(p[2]) + + def p_atom_expr_block_error(self, p): + '''atom : OCURL error CCURL ''' + p[0] = ErrorNode() + + def p_atom_id(self, p): + '''atom : ID''' + p[0] = IdNode(p.slice[1]) + + def p_atom_integer(self, p): + '''atom : INTEGER''' + p[0] = IntegerNode(p.slice[1]) + + def p_atom_string(self, p): + '''atom : STRING''' + p[0] = StringNode(p.slice[1]) + + def p_atom_bool(self, p): + '''atom : BOOL''' + p[0] = BoolNode(p.slice[1]) + + def p_error(self, p): + if p is None: + colm = find_column(self.lexer.lexer, self.lexer.lexer) + line = self.lexer.lexer.lineno + error = SyntacticError( + line, colm, 'ERROR at or near "%s"' % 'EOF') + self.error_list.append(error) + else: + error = SyntacticError( + p.lineno, p.lexpos, 'ERROR at or near "%s"' % p.lex) + self.error_list.append(error) diff --git a/src/engine/parser/parsetab.py b/src/engine/parser/parsetab.py new file mode 100644 index 00000000..af4d7ac4 --- /dev/null +++ b/src/engine/parser/parsetab.py @@ -0,0 +1,221 @@ + +# parsetab.py +# This file is automatically generated. Do not edit. +# pylint: disable=W,C,R +_tabversion = '3.10' + +_lr_method = 'LALR' + +_lr_signature = 'programrightASSIGNrightNOTnonassocLESSLESSEQUALEQUALleftPLUSMINUSleftSTARDIVrightISVOIDrightINT_COMPLEMENTleftATleftDOTACTION ASSIGN AT BOOL CASE CCURL CLASS COLON COMMA CPAR DIV DOT ELSE EQUAL ESAC FI ID IF IN INHERITS INTEGER INT_COMPLEMENT ISVOID LESS LESSEQUAL LET LOOP MINUS NEW NOT OCURL OF OPAR PLUS POOL SEMI STAR STRING THEN TYPE WHILEepsilon :program : class_listclass_list : def_class class_list\n | def_classclass_list : error class_list def_class : CLASS TYPE OCURL feature_list CCURL SEMI\n | CLASS TYPE INHERITS TYPE OCURL feature_list CCURL SEMI def_class : CLASS error OCURL feature_list CCURL SEMI\n | CLASS TYPE OCURL error CCURL SEMI\n | CLASS error OCURL error CCURL SEMI\n | CLASS TYPE INHERITS TYPE OCURL error CCURL SEMI\n | CLASS TYPE INHERITS error OCURL error CCURL SEMI\n | CLASS error INHERITS TYPE OCURL error CCURL SEMI\n | CLASS error INHERITS error OCURL feature_list CCURL SEMI\n | CLASS error INHERITS error OCURL error CCURL SEMI feature_list : feature feature_list\n | epsilonfeature_list : error feature_listfeature : ID COLON TYPE SEMI\n | ID COLON TYPE ASSIGN expr SEMI feature : error COLON TYPE\n | ID COLON error\n | error COLON error\n | error COLON TYPE ASSIGN expr\n | ID COLON error ASSIGN expr\n | ID COLON TYPE ASSIGN error\n | ID COLON error ASSIGN error\n | error COLON TYPE ASSIGN error\n | error COLON error ASSIGN expr\n | error COLON error ASSIGN errorfeature : ID OPAR param_list CPAR COLON TYPE OCURL expr CCURL SEMI\n | ID OPAR CPAR COLON TYPE OCURL expr CCURL SEMI feature : error OPAR param_list CPAR COLON TYPE OCURL expr CCURL SEMI\n | ID OPAR error CPAR COLON TYPE OCURL expr CCURL SEMI\n | ID OPAR param_list CPAR COLON error OCURL expr CCURL SEMI\n | ID OPAR param_list CPAR COLON TYPE OCURL error CCURL SEMI\n | error OPAR error CPAR COLON TYPE OCURL expr CCURL SEMI\n | error OPAR param_list CPAR COLON error OCURL expr CCURL SEMI\n | error OPAR param_list CPAR COLON TYPE OCURL error CCURL SEMI\n | ID OPAR error CPAR COLON error OCURL error CCURL SEMI\n | error OPAR error CPAR COLON TYPE OCURL error CCURL SEMI\n | error OPAR error CPAR COLON error OCURL error CCURL SEMI\n | error OPAR param_list CPAR COLON error OCURL error CCURL SEMI\n | error OPAR CPAR COLON TYPE OCURL expr CCURL SEMI\n | ID OPAR CPAR COLON error OCURL expr CCURL SEMI\n | ID OPAR CPAR COLON TYPE OCURL error CCURL SEMI\n | ID OPAR CPAR COLON error OCURL error CCURL SEMI\n | ID error CPAR COLON TYPE OCURL error CCURL SEMI\n | ID error CPAR COLON TYPE OCURL expr CCURL SEMI\n | ID error CPAR COLON error OCURL error CCURL SEMI param_list : param\n | param COMMA param_listparam : ID COLON TYPEexpr_block : expr SEMI\n | expr SEMI expr_blocklet_list : ID COLON TYPE\n | ID COLON TYPE ASSIGN expr\n | ID COLON TYPE COMMA let_list\n | ID COLON TYPE ASSIGN expr COMMA let_listlet_list : error COLON TYPE\n | ID COLON error\n | error COLON error \n | error COLON TYPE ASSIGN expr\n | ID COLON error ASSIGN expr\n | ID COLON TYPE ASSIGN error\n | ID COLON error ASSIGN error\n | error COLON error ASSIGN expr\n | error COLON TYPE ASSIGN error\n | error COLON error ASSIGN error\n | error COLON TYPE COMMA let_list\n | ID COLON error COMMA let_list\n | ID COLON TYPE COMMA error\n | ID COLON error COMMA error\n | error COLON error COMMA let_list\n | error COLON TYPE COMMA error\n | error COLON error COMMA error\n | error COLON error ASSIGN error COMMA error\n | ID COLON error ASSIGN error COMMA error\n | error COLON TYPE ASSIGN error COMMA error\n | ID COLON TYPE ASSIGN error COMMA error\n | error COLON error ASSIGN expr COMMA error\n | ID COLON error ASSIGN expr COMMA error\n | error COLON TYPE ASSIGN expr COMMA error\n | ID COLON TYPE ASSIGN expr COMMA error\n | error COLON error ASSIGN error COMMA let_list\n | ID COLON error ASSIGN error COMMA let_list\n | error COLON TYPE ASSIGN error COMMA let_list\n | ID COLON TYPE ASSIGN error COMMA let_list\n | error COLON error ASSIGN expr COMMA let_list\n | ID COLON error ASSIGN expr COMMA let_list\n | error COLON TYPE ASSIGN expr COMMA let_list case_list : ID COLON TYPE ACTION expr SEMI\n | ID COLON TYPE ACTION expr SEMI case_list case_list : error COLON TYPE ACTION expr SEMI\n | ID COLON error ACTION expr SEMI\n | ID COLON TYPE ACTION error SEMI\n | ID COLON TYPE error error SEMI\n | error COLON error ACTION expr SEMI\n | error COLON TYPE ACTION error SEMI\n | error COLON error ACTION error SEMI\n | error COLON TYPE ACTION expr SEMI case_list\n | ID COLON error ACTION expr SEMI case_list\n | ID COLON TYPE ACTION error SEMI case_list\n | ID COLON TYPE error error SEMI case_list\n | error COLON error ACTION expr SEMI case_list\n | error COLON TYPE ACTION error SEMI case_list\n | error COLON error ACTION error SEMI case_list\n | error COLON TYPE ACTION expr SEMI error\n | ID COLON TYPE ACTION expr SEMI error\n | ID COLON error ACTION expr SEMI error\n | ID COLON TYPE error error SEMI error\n | error COLON error ACTION expr SEMI error\n | error COLON TYPE ACTION error SEMI error\n | error COLON error ACTION error SEMI errorfunccall : ID OPAR CPAR\n | ID OPAR arg_list CPARfunccall : error OPAR CPAR\n | ID OPAR error CPAR\n | error OPAR arg_list CPAR\n | error OPAR error CPAR arg_list : expr\n | expr COMMA arg_list arg_list : error\n | error COMMA arg_listexpr : ID ASSIGN expr\n | operat expr : ID ASSIGN error \n | error ASSIGN expr operat : operat LESSEQUAL operat\n | operat LESS operat\n | operat EQUAL operatoperat : error LESSEQUAL operat\n | error LESSEQUAL error\n | operat LESSEQUAL error\n | error LESS operat\n | error LESS error\n | operat LESS error\n | error EQUAL operat\n | error EQUAL error\n | operat EQUAL erroroperat : operat PLUS operat\n | operat MINUS operat\n | operat STAR operat\n | operat DIV operat operat : operat PLUS error\n | error PLUS error\n | error PLUS operat\n | error MINUS operat\n | error MINUS error\n | operat MINUS error\n | operat STAR error\n | error STAR error\n | error STAR operat\n | operat DIV error \n | error DIV error \n | error DIV operat operat : baseopbaseop : subatom AT TYPE DOT funccall baseop : error AT TYPE DOT funccall\n | subatom AT error DOT funccall\n | subatom AT TYPE DOT error\n | error AT error DOT funccall\n | error AT TYPE DOT error\n | subatom AT error DOT error\n | error AT error DOT error baseop : subatomsubatom : OPAR expr CPARsubatom : error expr CPAR\n | OPAR expr errorsubatom : subatom DOT funccall subatom : subatom DOT error \n | error DOT funccall\n | error DOT error subatom : funccall subatom : INT_COMPLEMENT baseop\n | NOT operat\n | ISVOID baseop subatom : NOT error subatom : IF expr THEN expr ELSE expr FI\n | WHILE expr LOOP expr POOL\n | LET let_list IN expr \n | CASE expr OF case_list ESAC subatom : atomatom : NEW TYPEatom : NEW erroratom : OCURL expr_block CCURL atom : OCURL error CCURL atom : IDatom : INTEGERatom : STRINGatom : BOOL' + +_lr_action_items = {'error':([0,3,4,5,10,11,12,13,15,16,18,21,26,29,30,32,34,35,36,39,40,41,42,43,44,51,57,59,60,61,64,65,71,72,73,74,76,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,113,114,115,118,121,122,123,124,125,126,127,128,129,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,165,166,168,174,175,176,177,180,181,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,208,209,210,211,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,250,252,253,255,256,258,259,260,261,262,263,264,265,266,267,268,269,270,273,283,285,287,294,302,303,304,305,306,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,333,334,335,336,340,341,342,343,348,351,355,359,363,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,410,413,415,417,418,419,420,421,422,423,424,],[4,4,4,9,15,20,21,23,26,26,33,26,26,43,45,51,55,57,58,61,63,-6,-9,-23,-21,-22,26,-10,-8,26,84,105,-19,113,114,116,120,128,-29,-188,-126,-157,-166,-174,128,154,157,154,128,128,163,128,-183,166,168,-189,-190,-191,128,-24,170,172,128,128,-25,179,182,-7,-11,-12,-15,-14,-13,128,128,186,188,190,192,194,196,198,200,202,205,210,213,216,218,220,222,224,226,228,230,232,234,-175,128,-188,-176,128,-177,-184,-185,128,128,-20,249,250,255,256,-128,-168,128,-132,128,-135,128,-138,128,-147,128,-148,128,-153,128,-156,-173,-172,128,-117,234,-125,128,-115,128,-129,128,-130,128,-131,128,-141,128,-142,128,-143,128,-144,128,-170,-171,-167,-169,128,128,128,275,276,280,-186,-187,128,282,283,285,287,128,294,128,128,128,300,128,302,304,205,-120,306,-119,306,-116,-118,310,311,-181,128,128,128,128,-165,-162,-163,-159,128,-158,-161,-164,-160,128,-180,348,350,351,353,355,357,359,361,-182,364,365,-44,-50,-48,-49,-32,-46,-47,-45,128,128,128,128,389,-42,-41,-37,-43,-38,-39,-33,-31,-36,-35,-40,-34,-179,394,395,397,399,401,403,405,407,410,411,128,413,415,128,128,128,426,280,428,430,432,434,436,438,]),'CLASS':([0,3,4,41,42,59,60,122,123,124,125,126,127,],[5,5,5,-6,-9,-10,-8,-7,-11,-12,-15,-14,-13,]),'$end':([1,2,3,6,7,41,42,59,60,122,123,124,125,126,127,],[0,-2,-4,-3,-5,-6,-9,-10,-8,-7,-11,-12,-15,-14,-13,]),'TYPE':([5,11,13,29,32,68,70,74,76,100,107,108,118,121,138,150,238,239,324,325,],[8,19,24,44,50,109,111,117,119,165,171,173,178,183,201,229,274,277,363,366,]),'OCURL':([8,9,19,20,23,24,64,65,72,73,84,91,92,93,94,95,96,98,101,105,109,113,114,116,117,119,120,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,170,171,172,173,174,177,178,179,180,181,182,183,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[10,12,35,36,39,40,101,101,101,101,101,101,101,101,101,101,101,101,101,101,174,101,101,176,177,180,181,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,244,245,246,247,101,101,252,253,101,101,258,259,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,]),'INHERITS':([8,9,],[11,13,]),'ID':([10,12,15,16,21,26,30,34,35,39,43,44,51,57,61,64,65,69,71,72,73,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,101,102,103,104,105,106,113,114,115,128,129,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,147,148,149,151,153,154,155,156,157,158,165,166,168,174,175,177,180,181,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,209,210,211,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,235,236,237,240,241,242,243,245,246,247,250,252,253,255,256,259,260,261,262,263,264,265,266,267,268,269,270,273,283,285,287,294,302,303,304,305,306,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,333,334,335,336,340,341,342,343,348,351,355,359,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,390,391,392,410,413,415,417,418,419,420,421,422,423,424,],[18,18,18,18,18,18,49,49,18,18,-23,-21,-22,18,18,86,86,49,-19,86,86,86,-29,-188,-126,-157,-166,-174,86,155,155,155,86,86,162,86,-183,86,-189,-190,-191,86,-24,86,86,-25,86,86,155,155,155,155,155,155,155,204,86,86,86,155,155,155,155,155,155,155,204,-175,86,-188,-176,86,-177,-184,-185,86,86,-20,86,86,86,-128,-168,86,-132,86,-135,86,-138,86,-147,86,-148,86,-153,86,-156,-173,-172,86,-117,-125,86,-115,86,-129,86,-130,86,-131,86,-141,86,-142,86,-143,86,-144,86,-170,-171,-167,-169,86,86,86,279,-186,-187,86,86,86,86,86,86,86,86,86,86,204,204,86,-120,86,-119,86,-116,-118,204,204,-181,86,86,86,86,-165,-162,-163,-159,86,-158,-161,-164,-160,86,-180,86,162,86,162,86,162,86,162,-182,-44,-50,-48,-49,-32,-46,-47,-45,86,86,86,86,-42,-41,-37,-43,-38,-39,-33,-31,-36,-35,-40,-34,-179,162,162,162,162,162,162,162,162,86,86,86,86,86,86,86,279,279,279,279,279,279,279,279,]),'CCURL':([10,12,14,15,16,17,21,22,26,28,31,35,39,43,44,51,56,57,58,61,62,63,71,84,85,86,87,88,89,90,99,102,103,104,105,106,113,114,115,153,155,156,157,158,165,166,167,168,175,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,206,209,210,211,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,243,248,249,250,251,254,255,256,257,263,265,267,268,273,281,282,283,284,285,286,287,288,293,294,295,300,301,302,303,304,305,309,310,311,312,314,323,333,334,335,336,340,341,342,343,367,368,369,370,371,372,373,374,375,376,377,378,379,],[-1,-1,25,27,-1,-17,37,38,-1,-18,-16,-1,-1,-23,-21,-22,78,79,80,81,82,83,-19,-30,-29,-188,-126,-157,-166,-174,-183,-189,-190,-191,-28,-24,-26,-27,-25,-175,-188,-176,-178,-177,-184,-185,241,242,-20,-128,-168,-133,-132,-136,-135,-139,-138,-146,-147,-149,-148,-152,-153,-155,-156,-173,-172,-117,-125,-127,-115,-129,-134,-130,-137,-131,-140,-141,-145,-142,-150,-143,-151,-144,-154,-170,-171,-167,-169,-186,-187,-54,289,290,291,292,296,297,298,299,-120,-119,-116,-118,-181,-55,326,327,328,329,330,331,332,337,338,339,344,345,-165,-162,-163,-159,-158,-161,-164,-160,-180,-182,-44,-50,-48,-49,-32,-46,-47,-45,-42,-41,-37,-43,-38,-39,-33,-31,-36,-35,-40,-34,-179,]),'COLON':([15,18,21,26,47,49,52,54,57,61,66,67,75,77,162,163,279,280,350,353,357,361,394,395,397,399,401,403,405,407,426,428,430,432,434,436,438,],[29,32,29,29,68,70,74,76,29,29,107,108,118,121,238,239,324,325,239,239,239,239,239,239,239,239,239,239,239,239,325,325,325,325,325,325,325,]),'OPAR':([15,18,21,26,57,61,64,65,72,73,84,86,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,155,157,168,174,177,180,181,186,188,190,192,194,196,198,202,204,205,210,213,216,218,220,222,224,226,228,232,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,302,304,306,310,311,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[30,34,30,30,30,30,91,91,91,91,140,142,91,91,91,91,91,91,91,91,140,140,140,140,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,140,142,140,140,91,91,91,91,140,140,140,140,140,140,140,262,142,140,140,140,140,140,140,140,140,140,140,262,91,91,91,91,91,91,91,140,91,91,140,140,91,91,91,91,140,140,140,140,262,262,140,262,262,91,91,91,91,91,140,140,140,140,91,91,91,91,140,140,140,]),'SEMI':([25,27,37,38,50,78,79,80,81,82,83,86,87,88,89,90,99,102,103,104,112,153,155,156,157,158,165,166,169,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,206,209,210,211,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,263,265,267,268,273,289,290,291,292,296,297,298,299,302,303,304,305,309,310,311,312,314,323,326,327,328,329,330,331,332,337,338,339,344,345,379,409,410,411,412,413,414,415,416,],[41,42,59,60,71,122,123,124,125,126,127,-188,-126,-157,-166,-174,-183,-189,-190,-191,175,-175,-188,-176,-178,-177,-184,-185,243,-128,-168,-133,-132,-136,-135,-139,-138,-146,-147,-149,-148,-152,-153,-155,-156,-173,-172,-117,-125,-127,-115,-129,-134,-130,-137,-131,-140,-141,-145,-142,-150,-143,-151,-144,-154,-170,-171,-167,-169,-186,-187,-120,-119,-116,-118,-181,333,334,335,336,340,341,342,343,-165,-162,-163,-159,-158,-161,-164,-160,-180,-182,367,368,369,370,371,372,373,374,375,376,377,378,-179,417,418,419,420,421,422,423,424,]),'CPAR':([30,33,34,45,46,48,53,55,86,87,88,89,90,99,102,103,104,110,111,130,140,142,152,153,155,156,157,158,165,166,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,262,263,265,267,268,273,302,303,304,305,306,307,308,309,310,311,312,314,323,379,],[47,52,54,66,67,-51,75,77,-188,-126,-157,-166,-174,-183,-189,-190,-191,-52,-53,185,206,211,233,-175,-188,-176,-178,-177,-184,-185,-128,-168,-133,-132,-136,-135,-139,-138,-146,-147,-149,-148,-152,-153,-155,-156,-173,-172,263,-117,265,233,-125,-127,-115,267,268,-121,-129,-134,-130,-137,-131,-140,-141,-145,-142,-150,-143,-151,-144,-154,-170,-171,-167,-169,-186,-187,206,-120,-119,-116,-118,-181,-165,-162,-163,-159,-123,-124,-122,-158,-161,-164,-160,-180,-182,-179,]),'ASSIGN':([43,44,50,51,84,86,105,113,114,128,168,205,210,213,250,255,256,274,275,276,277,283,285,287,294,306,348,351,355,359,410,413,415,],[64,65,72,73,129,141,129,129,129,129,129,129,129,129,129,129,129,315,317,319,321,129,129,129,129,129,129,129,129,129,129,129,129,]),'COMMA':([48,86,87,88,89,90,99,102,103,104,111,153,155,156,157,158,165,166,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,208,209,210,211,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,263,265,267,268,273,274,275,276,277,302,303,304,305,306,309,310,311,312,314,323,347,348,351,352,355,356,359,360,379,],[69,-188,-126,-157,-166,-174,-183,-189,-190,-191,-53,-175,-188,-176,-178,-177,-184,-185,-128,-168,-133,-132,-136,-135,-139,-138,-146,-147,-149,-148,-152,-153,-155,-156,-173,-172,264,-117,266,-125,-127,-115,264,266,-129,-134,-130,-137,-131,-140,-141,-145,-142,-150,-143,-151,-144,-154,-170,-171,-167,-169,-186,-187,-120,-119,-116,-118,-181,316,318,320,322,-165,-162,-163,-159,264,-158,-161,-164,-160,-180,-182,380,381,382,383,384,385,386,387,-179,]),'INT_COMPLEMENT':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,]),'NOT':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,]),'ISVOID':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,]),'IF':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,]),'WHILE':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,]),'LET':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,]),'CASE':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,]),'NEW':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,]),'INTEGER':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,]),'STRING':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,]),'BOOL':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,]),'LESSEQUAL':([84,86,87,88,89,90,99,102,103,104,105,113,114,128,153,155,156,157,158,165,166,168,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,209,210,211,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,250,255,256,263,265,267,268,273,283,285,287,294,302,303,304,305,306,309,310,311,312,314,323,348,351,355,359,379,410,413,415,],[131,-188,143,-157,-166,-174,-183,-189,-190,-191,131,131,131,131,-175,-188,143,131,-177,-184,-185,131,-128,-168,131,143,131,143,131,143,131,-147,131,-148,131,-153,131,-156,-173,-172,131,-117,-125,131,-115,131,143,131,143,131,143,131,-141,131,-142,131,-143,131,-144,131,-170,-171,-167,-169,-186,-187,131,131,131,-120,-119,-116,-118,-181,131,131,131,131,-165,-162,-163,-159,131,-158,-161,-164,-160,-180,-182,131,131,131,131,-179,131,131,131,]),'LESS':([84,86,87,88,89,90,99,102,103,104,105,113,114,128,153,155,156,157,158,165,166,168,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,209,210,211,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,250,255,256,263,265,267,268,273,283,285,287,294,302,303,304,305,306,309,310,311,312,314,323,348,351,355,359,379,410,413,415,],[132,-188,144,-157,-166,-174,-183,-189,-190,-191,132,132,132,132,-175,-188,144,132,-177,-184,-185,132,-128,-168,132,144,132,144,132,144,132,-147,132,-148,132,-153,132,-156,-173,-172,132,-117,-125,132,-115,132,144,132,144,132,144,132,-141,132,-142,132,-143,132,-144,132,-170,-171,-167,-169,-186,-187,132,132,132,-120,-119,-116,-118,-181,132,132,132,132,-165,-162,-163,-159,132,-158,-161,-164,-160,-180,-182,132,132,132,132,-179,132,132,132,]),'EQUAL':([84,86,87,88,89,90,99,102,103,104,105,113,114,128,153,155,156,157,158,165,166,168,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,209,210,211,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,250,255,256,263,265,267,268,273,283,285,287,294,302,303,304,305,306,309,310,311,312,314,323,348,351,355,359,379,410,413,415,],[133,-188,145,-157,-166,-174,-183,-189,-190,-191,133,133,133,133,-175,-188,145,133,-177,-184,-185,133,-128,-168,133,145,133,145,133,145,133,-147,133,-148,133,-153,133,-156,-173,-172,133,-117,-125,133,-115,133,145,133,145,133,145,133,-141,133,-142,133,-143,133,-144,133,-170,-171,-167,-169,-186,-187,133,133,133,-120,-119,-116,-118,-181,133,133,133,133,-165,-162,-163,-159,133,-158,-161,-164,-160,-180,-182,133,133,133,133,-179,133,133,133,]),'PLUS':([84,86,87,88,89,90,99,102,103,104,105,113,114,128,153,155,156,157,158,165,166,168,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,209,210,211,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,250,255,256,263,265,267,268,273,283,285,287,294,302,303,304,305,306,309,310,311,312,314,323,348,351,355,359,379,410,413,415,],[134,-188,146,-157,-166,-174,-183,-189,-190,-191,134,134,134,134,-175,-188,146,134,-177,-184,-185,134,-128,-168,134,146,134,146,134,146,134,-147,134,-148,134,-153,134,-156,-173,-172,134,-117,-125,134,-115,134,146,134,146,134,146,134,-141,134,-142,134,-143,134,-144,134,-170,-171,-167,-169,-186,-187,134,134,134,-120,-119,-116,-118,-181,134,134,134,134,-165,-162,-163,-159,134,-158,-161,-164,-160,-180,-182,134,134,134,134,-179,134,134,134,]),'MINUS':([84,86,87,88,89,90,99,102,103,104,105,113,114,128,153,155,156,157,158,165,166,168,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,209,210,211,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,250,255,256,263,265,267,268,273,283,285,287,294,302,303,304,305,306,309,310,311,312,314,323,348,351,355,359,379,410,413,415,],[135,-188,147,-157,-166,-174,-183,-189,-190,-191,135,135,135,135,-175,-188,147,135,-177,-184,-185,135,-128,-168,135,147,135,147,135,147,135,-147,135,-148,135,-153,135,-156,-173,-172,135,-117,-125,135,-115,135,147,135,147,135,147,135,-141,135,-142,135,-143,135,-144,135,-170,-171,-167,-169,-186,-187,135,135,135,-120,-119,-116,-118,-181,135,135,135,135,-165,-162,-163,-159,135,-158,-161,-164,-160,-180,-182,135,135,135,135,-179,135,135,135,]),'STAR':([84,86,87,88,89,90,99,102,103,104,105,113,114,128,153,155,156,157,158,165,166,168,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,209,210,211,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,250,255,256,263,265,267,268,273,283,285,287,294,302,303,304,305,306,309,310,311,312,314,323,348,351,355,359,379,410,413,415,],[136,-188,148,-157,-166,-174,-183,-189,-190,-191,136,136,136,136,-175,-188,148,136,-177,-184,-185,136,-128,-168,136,148,136,148,136,148,136,148,136,148,136,-153,136,-156,-173,-172,136,-117,-125,136,-115,136,148,136,148,136,148,136,148,136,148,136,-143,136,-144,136,-170,-171,-167,-169,-186,-187,136,136,136,-120,-119,-116,-118,-181,136,136,136,136,-165,-162,-163,-159,136,-158,-161,-164,-160,-180,-182,136,136,136,136,-179,136,136,136,]),'DIV':([84,86,87,88,89,90,99,102,103,104,105,113,114,128,153,155,156,157,158,165,166,168,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,209,210,211,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,250,255,256,263,265,267,268,273,283,285,287,294,302,303,304,305,306,309,310,311,312,314,323,348,351,355,359,379,410,413,415,],[137,-188,149,-157,-166,-174,-183,-189,-190,-191,137,137,137,137,-175,-188,149,137,-177,-184,-185,137,-128,-168,137,149,137,149,137,149,137,149,137,149,137,-153,137,-156,-173,-172,137,-117,-125,137,-115,137,149,137,149,137,149,137,149,137,149,137,-143,137,-144,137,-170,-171,-167,-169,-186,-187,137,137,137,-120,-119,-116,-118,-181,137,137,137,137,-165,-162,-163,-159,137,-158,-161,-164,-160,-180,-182,137,137,137,137,-179,137,137,137,]),'AT':([84,86,87,88,89,90,99,102,103,104,105,113,114,128,153,154,155,156,157,158,165,166,168,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,205,206,209,210,211,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,250,255,256,263,265,267,268,273,283,285,287,294,302,303,304,305,306,309,310,311,312,314,323,348,351,355,359,379,410,413,415,],[138,-188,-126,-157,150,-174,-183,-189,-190,-191,138,138,138,138,-175,138,-188,-176,138,-177,-184,-185,138,-128,-168,138,-132,138,-135,138,-138,138,-147,138,-148,138,-153,138,-156,-173,-172,138,-117,-125,138,-115,138,-129,138,-130,138,-131,138,-141,138,-142,138,-143,138,-144,138,-170,-171,-167,-169,-186,-187,138,138,138,-120,-119,-116,-118,-181,138,138,138,138,-165,-162,-163,-159,138,-158,-161,-164,-160,-180,-182,138,138,138,138,-179,138,138,138,]),'DOT':([84,86,87,88,89,90,99,102,103,104,105,113,114,128,153,154,155,156,157,158,165,166,168,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,205,206,209,210,211,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,241,242,250,255,256,263,265,267,268,273,283,285,287,294,302,303,304,305,306,309,310,311,312,314,323,348,351,355,359,379,410,413,415,],[139,-188,-126,-157,151,-174,-183,-189,-190,-191,139,139,139,139,-175,139,-188,-176,139,-177,-184,-185,139,-128,-168,139,-132,139,-135,139,-138,139,-147,139,-148,139,-153,139,-156,260,261,-173,-172,139,-117,-125,139,-115,139,-129,139,-130,139,-131,139,-141,139,-142,139,-143,139,-144,139,269,270,-170,-171,-167,-169,-186,-187,139,139,139,-120,-119,-116,-118,-181,139,139,139,139,-165,-162,-163,-159,139,-158,-161,-164,-160,-180,-182,139,139,139,139,-179,139,139,139,]),'THEN':([86,87,88,89,90,99,102,103,104,153,155,156,157,158,159,165,166,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,206,209,210,211,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,263,265,267,268,273,302,303,304,305,309,310,311,312,314,323,379,],[-188,-126,-157,-166,-174,-183,-189,-190,-191,-175,-188,-176,-178,-177,235,-184,-185,-128,-168,-133,-132,-136,-135,-139,-138,-146,-147,-149,-148,-152,-153,-155,-156,-173,-172,-117,-125,-127,-115,-129,-134,-130,-137,-131,-140,-141,-145,-142,-150,-143,-151,-144,-154,-170,-171,-167,-169,-186,-187,-120,-119,-116,-118,-181,-165,-162,-163,-159,-158,-161,-164,-160,-180,-182,-179,]),'LOOP':([86,87,88,89,90,99,102,103,104,153,155,156,157,158,160,165,166,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,206,209,210,211,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,263,265,267,268,273,302,303,304,305,309,310,311,312,314,323,379,],[-188,-126,-157,-166,-174,-183,-189,-190,-191,-175,-188,-176,-178,-177,236,-184,-185,-128,-168,-133,-132,-136,-135,-139,-138,-146,-147,-149,-148,-152,-153,-155,-156,-173,-172,-117,-125,-127,-115,-129,-134,-130,-137,-131,-140,-141,-145,-142,-150,-143,-151,-144,-154,-170,-171,-167,-169,-186,-187,-120,-119,-116,-118,-181,-165,-162,-163,-159,-158,-161,-164,-160,-180,-182,-179,]),'OF':([86,87,88,89,90,99,102,103,104,153,155,156,157,158,164,165,166,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,206,209,210,211,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,263,265,267,268,273,302,303,304,305,309,310,311,312,314,323,379,],[-188,-126,-157,-166,-174,-183,-189,-190,-191,-175,-188,-176,-178,-177,240,-184,-185,-128,-168,-133,-132,-136,-135,-139,-138,-146,-147,-149,-148,-152,-153,-155,-156,-173,-172,-117,-125,-127,-115,-129,-134,-130,-137,-131,-140,-141,-145,-142,-150,-143,-151,-144,-154,-170,-171,-167,-169,-186,-187,-120,-119,-116,-118,-181,-165,-162,-163,-159,-158,-161,-164,-160,-180,-182,-179,]),'ELSE':([86,87,88,89,90,99,102,103,104,153,155,156,157,158,165,166,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,206,209,210,211,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,263,265,267,268,271,273,302,303,304,305,309,310,311,312,314,323,379,],[-188,-126,-157,-166,-174,-183,-189,-190,-191,-175,-188,-176,-178,-177,-184,-185,-128,-168,-133,-132,-136,-135,-139,-138,-146,-147,-149,-148,-152,-153,-155,-156,-173,-172,-117,-125,-127,-115,-129,-134,-130,-137,-131,-140,-141,-145,-142,-150,-143,-151,-144,-154,-170,-171,-167,-169,-186,-187,-120,-119,-116,-118,313,-181,-165,-162,-163,-159,-158,-161,-164,-160,-180,-182,-179,]),'POOL':([86,87,88,89,90,99,102,103,104,153,155,156,157,158,165,166,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,206,209,210,211,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,263,265,267,268,272,273,302,303,304,305,309,310,311,312,314,323,379,],[-188,-126,-157,-166,-174,-183,-189,-190,-191,-175,-188,-176,-178,-177,-184,-185,-128,-168,-133,-132,-136,-135,-139,-138,-146,-147,-149,-148,-152,-153,-155,-156,-173,-172,-117,-125,-127,-115,-129,-134,-130,-137,-131,-140,-141,-145,-142,-150,-143,-151,-144,-154,-170,-171,-167,-169,-186,-187,-120,-119,-116,-118,314,-181,-165,-162,-163,-159,-158,-161,-164,-160,-180,-182,-179,]),'FI':([86,87,88,89,90,99,102,103,104,153,155,156,157,158,165,166,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,206,209,210,211,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,263,265,267,268,273,302,303,304,305,309,310,311,312,314,323,346,379,],[-188,-126,-157,-166,-174,-183,-189,-190,-191,-175,-188,-176,-178,-177,-184,-185,-128,-168,-133,-132,-136,-135,-139,-138,-146,-147,-149,-148,-152,-153,-155,-156,-173,-172,-117,-125,-127,-115,-129,-134,-130,-137,-131,-140,-141,-145,-142,-150,-143,-151,-144,-154,-170,-171,-167,-169,-186,-187,-120,-119,-116,-118,-181,-165,-162,-163,-159,-158,-161,-164,-160,-180,-182,379,-179,]),'IN':([86,87,88,89,90,99,102,103,104,153,155,156,157,158,161,165,166,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,202,203,206,209,210,211,215,216,217,218,219,220,221,222,223,224,225,226,227,228,231,232,233,234,241,242,263,265,267,268,273,274,275,276,277,302,303,304,305,309,310,311,312,314,323,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,379,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,],[-188,-126,-157,-166,-174,-183,-189,-190,-191,-175,-188,-176,-178,-177,237,-184,-185,-128,-168,-133,-132,-136,-135,-139,-138,-146,-147,-149,-148,-152,-153,-155,-156,-173,-172,-117,-125,-127,-115,-129,-134,-130,-137,-131,-140,-141,-145,-142,-150,-143,-151,-144,-154,-170,-171,-167,-169,-186,-187,-120,-119,-116,-118,-181,-56,-61,-62,-60,-165,-162,-163,-159,-158,-161,-164,-160,-180,-182,-57,-65,-58,-72,-66,-64,-73,-71,-69,-67,-76,-74,-68,-63,-75,-70,-179,-59,-84,-80,-88,-78,-86,-82,-90,-77,-85,-81,-89,-79,-87,-83,-91,]),'ESAC':([278,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,],[323,-92,-96,-97,-95,-100,-98,-99,-94,-93,-109,-103,-111,-104,-110,-102,-114,-107,-112,-105,-113,-106,-108,-101,]),'ACTION':([363,364,365,366,],[388,390,391,392,]),} + +_lr_action = {} +for _k, _v in _lr_action_items.items(): + for _x,_y in zip(_v[0],_v[1]): + if not _x in _lr_action: _lr_action[_x] = {} + _lr_action[_x][_k] = _y +del _lr_action_items + +_lr_goto_items = {'program':([0,],[1,]),'class_list':([0,3,4,],[2,6,7,]),'def_class':([0,3,4,],[3,3,3,]),'feature_list':([10,12,15,16,21,26,35,39,57,61,],[14,22,28,31,28,28,56,62,28,28,]),'feature':([10,12,15,16,21,26,35,39,57,61,],[16,16,16,16,16,16,16,16,16,16,]),'epsilon':([10,12,15,16,21,26,35,39,57,61,],[17,17,17,17,17,17,17,17,17,17,]),'param_list':([30,34,69,],[46,53,110,]),'param':([30,34,69,],[48,48,48,]),'expr':([64,65,72,73,84,91,95,96,98,101,105,113,114,128,129,140,141,142,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[85,106,112,115,130,152,159,160,164,169,130,130,130,130,184,208,209,214,130,130,130,248,251,254,257,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,271,272,273,169,284,286,288,130,293,295,130,130,301,214,214,214,130,130,130,130,130,346,347,352,356,360,130,130,130,130,409,412,414,416,130,130,130,]),'operat':([64,65,72,73,84,91,93,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[87,87,87,87,87,87,156,87,87,87,87,87,87,87,87,87,187,189,191,193,195,197,199,87,87,87,215,217,219,221,223,225,227,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,]),'baseop':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[88,88,88,88,88,88,153,88,158,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,]),'subatom':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,]),'funccall':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,147,148,149,151,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,260,261,262,264,266,269,270,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,203,90,90,90,90,90,90,90,90,90,90,231,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,303,305,90,90,90,309,312,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,]),'atom':([64,65,72,73,84,91,92,93,94,95,96,98,101,105,113,114,128,129,131,132,133,134,135,136,137,140,141,142,143,144,145,146,147,148,149,154,157,168,174,177,180,181,186,188,190,192,194,196,198,205,210,213,216,218,220,222,224,226,228,235,236,237,243,245,246,247,250,252,253,255,256,259,262,264,266,283,285,287,294,306,313,315,317,319,321,348,351,355,359,388,390,391,392,410,413,415,],[99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,]),'let_list':([97,316,318,320,322,380,381,382,383,384,385,386,387,],[161,349,354,358,362,393,396,398,400,402,404,406,408,]),'expr_block':([101,243,],[167,281,]),'arg_list':([140,142,262,264,266,],[207,212,207,307,308,]),'case_list':([240,417,418,419,420,421,422,423,424,],[278,425,427,429,431,433,435,437,439,]),} + +_lr_goto = {} +for _k, _v in _lr_goto_items.items(): + for _x, _y in zip(_v[0], _v[1]): + if not _x in _lr_goto: _lr_goto[_x] = {} + _lr_goto[_x][_k] = _y +del _lr_goto_items +_lr_productions = [ + ("S' -> program","S'",1,None,None,None), + ('epsilon -> ','epsilon',0,'p_epsilon','cool_parser.py',38), + ('program -> class_list','program',1,'p_program','cool_parser.py',42), + ('class_list -> def_class class_list','class_list',2,'p_class_list','cool_parser.py',46), + ('class_list -> def_class','class_list',1,'p_class_list','cool_parser.py',47), + ('class_list -> error class_list','class_list',2,'p_class_list_error','cool_parser.py',54), + ('def_class -> CLASS TYPE OCURL feature_list CCURL SEMI','def_class',6,'p_def_class','cool_parser.py',61), + ('def_class -> CLASS TYPE INHERITS TYPE OCURL feature_list CCURL SEMI','def_class',8,'p_def_class','cool_parser.py',62), + ('def_class -> CLASS error OCURL feature_list CCURL SEMI','def_class',6,'p_def_class_error','cool_parser.py',70), + ('def_class -> CLASS TYPE OCURL error CCURL SEMI','def_class',6,'p_def_class_error','cool_parser.py',71), + ('def_class -> CLASS error OCURL error CCURL SEMI','def_class',6,'p_def_class_error','cool_parser.py',72), + ('def_class -> CLASS TYPE INHERITS TYPE OCURL error CCURL SEMI','def_class',8,'p_def_class_error','cool_parser.py',73), + ('def_class -> CLASS TYPE INHERITS error OCURL error CCURL SEMI','def_class',8,'p_def_class_error','cool_parser.py',74), + ('def_class -> CLASS error INHERITS TYPE OCURL error CCURL SEMI','def_class',8,'p_def_class_error','cool_parser.py',75), + ('def_class -> CLASS error INHERITS error OCURL feature_list CCURL SEMI','def_class',8,'p_def_class_error','cool_parser.py',76), + ('def_class -> CLASS error INHERITS error OCURL error CCURL SEMI','def_class',8,'p_def_class_error','cool_parser.py',77), + ('feature_list -> feature feature_list','feature_list',2,'p_feature_list','cool_parser.py',81), + ('feature_list -> epsilon','feature_list',1,'p_feature_list','cool_parser.py',82), + ('feature_list -> error feature_list','feature_list',2,'p_feature_list_error','cool_parser.py',89), + ('feature -> ID COLON TYPE SEMI','feature',4,'p_feature_attribute','cool_parser.py',93), + ('feature -> ID COLON TYPE ASSIGN expr SEMI','feature',6,'p_feature_attribute','cool_parser.py',94), + ('feature -> error COLON TYPE','feature',3,'p_def_attribute_error','cool_parser.py',102), + ('feature -> ID COLON error','feature',3,'p_def_attribute_error','cool_parser.py',103), + ('feature -> error COLON error','feature',3,'p_def_attribute_error','cool_parser.py',104), + ('feature -> error COLON TYPE ASSIGN expr','feature',5,'p_def_attribute_error','cool_parser.py',105), + ('feature -> ID COLON error ASSIGN expr','feature',5,'p_def_attribute_error','cool_parser.py',106), + ('feature -> ID COLON TYPE ASSIGN error','feature',5,'p_def_attribute_error','cool_parser.py',107), + ('feature -> ID COLON error ASSIGN error','feature',5,'p_def_attribute_error','cool_parser.py',108), + ('feature -> error COLON TYPE ASSIGN error','feature',5,'p_def_attribute_error','cool_parser.py',109), + ('feature -> error COLON error ASSIGN expr','feature',5,'p_def_attribute_error','cool_parser.py',110), + ('feature -> error COLON error ASSIGN error','feature',5,'p_def_attribute_error','cool_parser.py',111), + ('feature -> ID OPAR param_list CPAR COLON TYPE OCURL expr CCURL SEMI','feature',10,'p_feature_function','cool_parser.py',115), + ('feature -> ID OPAR CPAR COLON TYPE OCURL expr CCURL SEMI','feature',9,'p_feature_function','cool_parser.py',116), + ('feature -> error OPAR param_list CPAR COLON TYPE OCURL expr CCURL SEMI','feature',10,'p_feature_function_error','cool_parser.py',125), + ('feature -> ID OPAR error CPAR COLON TYPE OCURL expr CCURL SEMI','feature',10,'p_feature_function_error','cool_parser.py',126), + ('feature -> ID OPAR param_list CPAR COLON error OCURL expr CCURL SEMI','feature',10,'p_feature_function_error','cool_parser.py',127), + ('feature -> ID OPAR param_list CPAR COLON TYPE OCURL error CCURL SEMI','feature',10,'p_feature_function_error','cool_parser.py',128), + ('feature -> error OPAR error CPAR COLON TYPE OCURL expr CCURL SEMI','feature',10,'p_feature_function_error','cool_parser.py',129), + ('feature -> error OPAR param_list CPAR COLON error OCURL expr CCURL SEMI','feature',10,'p_feature_function_error','cool_parser.py',130), + ('feature -> error OPAR param_list CPAR COLON TYPE OCURL error CCURL SEMI','feature',10,'p_feature_function_error','cool_parser.py',131), + ('feature -> ID OPAR error CPAR COLON error OCURL error CCURL SEMI','feature',10,'p_feature_function_error','cool_parser.py',132), + ('feature -> error OPAR error CPAR COLON TYPE OCURL error CCURL SEMI','feature',10,'p_feature_function_error','cool_parser.py',133), + ('feature -> error OPAR error CPAR COLON error OCURL error CCURL SEMI','feature',10,'p_feature_function_error','cool_parser.py',134), + ('feature -> error OPAR param_list CPAR COLON error OCURL error CCURL SEMI','feature',10,'p_feature_function_error','cool_parser.py',135), + ('feature -> error OPAR CPAR COLON TYPE OCURL expr CCURL SEMI','feature',9,'p_feature_function_error','cool_parser.py',136), + ('feature -> ID OPAR CPAR COLON error OCURL expr CCURL SEMI','feature',9,'p_feature_function_error','cool_parser.py',137), + ('feature -> ID OPAR CPAR COLON TYPE OCURL error CCURL SEMI','feature',9,'p_feature_function_error','cool_parser.py',138), + ('feature -> ID OPAR CPAR COLON error OCURL error CCURL SEMI','feature',9,'p_feature_function_error','cool_parser.py',139), + ('feature -> ID error CPAR COLON TYPE OCURL error CCURL SEMI','feature',9,'p_feature_function_error','cool_parser.py',140), + ('feature -> ID error CPAR COLON TYPE OCURL expr CCURL SEMI','feature',9,'p_feature_function_error','cool_parser.py',141), + ('feature -> ID error CPAR COLON error OCURL error CCURL SEMI','feature',9,'p_feature_function_error','cool_parser.py',142), + ('param_list -> param','param_list',1,'p_param_list','cool_parser.py',146), + ('param_list -> param COMMA param_list','param_list',3,'p_param_list','cool_parser.py',147), + ('param -> ID COLON TYPE','param',3,'p_param','cool_parser.py',154), + ('expr_block -> expr SEMI','expr_block',2,'p_expr_block','cool_parser.py',158), + ('expr_block -> expr SEMI expr_block','expr_block',3,'p_expr_block','cool_parser.py',159), + ('let_list -> ID COLON TYPE','let_list',3,'p_let_list','cool_parser.py',166), + ('let_list -> ID COLON TYPE ASSIGN expr','let_list',5,'p_let_list','cool_parser.py',167), + ('let_list -> ID COLON TYPE COMMA let_list','let_list',5,'p_let_list','cool_parser.py',168), + ('let_list -> ID COLON TYPE ASSIGN expr COMMA let_list','let_list',7,'p_let_list','cool_parser.py',169), + ('let_list -> error COLON TYPE','let_list',3,'p_let_list_error','cool_parser.py',183), + ('let_list -> ID COLON error','let_list',3,'p_let_list_error','cool_parser.py',184), + ('let_list -> error COLON error','let_list',3,'p_let_list_error','cool_parser.py',185), + ('let_list -> error COLON TYPE ASSIGN expr','let_list',5,'p_let_list_error','cool_parser.py',186), + ('let_list -> ID COLON error ASSIGN expr','let_list',5,'p_let_list_error','cool_parser.py',187), + ('let_list -> ID COLON TYPE ASSIGN error','let_list',5,'p_let_list_error','cool_parser.py',188), + ('let_list -> ID COLON error ASSIGN error','let_list',5,'p_let_list_error','cool_parser.py',189), + ('let_list -> error COLON error ASSIGN expr','let_list',5,'p_let_list_error','cool_parser.py',190), + ('let_list -> error COLON TYPE ASSIGN error','let_list',5,'p_let_list_error','cool_parser.py',191), + ('let_list -> error COLON error ASSIGN error','let_list',5,'p_let_list_error','cool_parser.py',192), + ('let_list -> error COLON TYPE COMMA let_list','let_list',5,'p_let_list_error','cool_parser.py',193), + ('let_list -> ID COLON error COMMA let_list','let_list',5,'p_let_list_error','cool_parser.py',194), + ('let_list -> ID COLON TYPE COMMA error','let_list',5,'p_let_list_error','cool_parser.py',195), + ('let_list -> ID COLON error COMMA error','let_list',5,'p_let_list_error','cool_parser.py',196), + ('let_list -> error COLON error COMMA let_list','let_list',5,'p_let_list_error','cool_parser.py',197), + ('let_list -> error COLON TYPE COMMA error','let_list',5,'p_let_list_error','cool_parser.py',198), + ('let_list -> error COLON error COMMA error','let_list',5,'p_let_list_error','cool_parser.py',199), + ('let_list -> error COLON error ASSIGN error COMMA error','let_list',7,'p_let_list_error','cool_parser.py',200), + ('let_list -> ID COLON error ASSIGN error COMMA error','let_list',7,'p_let_list_error','cool_parser.py',201), + ('let_list -> error COLON TYPE ASSIGN error COMMA error','let_list',7,'p_let_list_error','cool_parser.py',202), + ('let_list -> ID COLON TYPE ASSIGN error COMMA error','let_list',7,'p_let_list_error','cool_parser.py',203), + ('let_list -> error COLON error ASSIGN expr COMMA error','let_list',7,'p_let_list_error','cool_parser.py',204), + ('let_list -> ID COLON error ASSIGN expr COMMA error','let_list',7,'p_let_list_error','cool_parser.py',205), + ('let_list -> error COLON TYPE ASSIGN expr COMMA error','let_list',7,'p_let_list_error','cool_parser.py',206), + ('let_list -> ID COLON TYPE ASSIGN expr COMMA error','let_list',7,'p_let_list_error','cool_parser.py',207), + ('let_list -> error COLON error ASSIGN error COMMA let_list','let_list',7,'p_let_list_error','cool_parser.py',208), + ('let_list -> ID COLON error ASSIGN error COMMA let_list','let_list',7,'p_let_list_error','cool_parser.py',209), + ('let_list -> error COLON TYPE ASSIGN error COMMA let_list','let_list',7,'p_let_list_error','cool_parser.py',210), + ('let_list -> ID COLON TYPE ASSIGN error COMMA let_list','let_list',7,'p_let_list_error','cool_parser.py',211), + ('let_list -> error COLON error ASSIGN expr COMMA let_list','let_list',7,'p_let_list_error','cool_parser.py',212), + ('let_list -> ID COLON error ASSIGN expr COMMA let_list','let_list',7,'p_let_list_error','cool_parser.py',213), + ('let_list -> error COLON TYPE ASSIGN expr COMMA let_list','let_list',7,'p_let_list_error','cool_parser.py',214), + ('case_list -> ID COLON TYPE ACTION expr SEMI','case_list',6,'p_case_list','cool_parser.py',218), + ('case_list -> ID COLON TYPE ACTION expr SEMI case_list','case_list',7,'p_case_list','cool_parser.py',219), + ('case_list -> error COLON TYPE ACTION expr SEMI','case_list',6,'p_case_list_error','cool_parser.py',228), + ('case_list -> ID COLON error ACTION expr SEMI','case_list',6,'p_case_list_error','cool_parser.py',229), + ('case_list -> ID COLON TYPE ACTION error SEMI','case_list',6,'p_case_list_error','cool_parser.py',230), + ('case_list -> ID COLON TYPE error error SEMI','case_list',6,'p_case_list_error','cool_parser.py',231), + ('case_list -> error COLON error ACTION expr SEMI','case_list',6,'p_case_list_error','cool_parser.py',232), + ('case_list -> error COLON TYPE ACTION error SEMI','case_list',6,'p_case_list_error','cool_parser.py',233), + ('case_list -> error COLON error ACTION error SEMI','case_list',6,'p_case_list_error','cool_parser.py',234), + ('case_list -> error COLON TYPE ACTION expr SEMI case_list','case_list',7,'p_case_list_error','cool_parser.py',235), + ('case_list -> ID COLON error ACTION expr SEMI case_list','case_list',7,'p_case_list_error','cool_parser.py',236), + ('case_list -> ID COLON TYPE ACTION error SEMI case_list','case_list',7,'p_case_list_error','cool_parser.py',237), + ('case_list -> ID COLON TYPE error error SEMI case_list','case_list',7,'p_case_list_error','cool_parser.py',238), + ('case_list -> error COLON error ACTION expr SEMI case_list','case_list',7,'p_case_list_error','cool_parser.py',239), + ('case_list -> error COLON TYPE ACTION error SEMI case_list','case_list',7,'p_case_list_error','cool_parser.py',240), + ('case_list -> error COLON error ACTION error SEMI case_list','case_list',7,'p_case_list_error','cool_parser.py',241), + ('case_list -> error COLON TYPE ACTION expr SEMI error','case_list',7,'p_case_list_error','cool_parser.py',242), + ('case_list -> ID COLON TYPE ACTION expr SEMI error','case_list',7,'p_case_list_error','cool_parser.py',243), + ('case_list -> ID COLON error ACTION expr SEMI error','case_list',7,'p_case_list_error','cool_parser.py',244), + ('case_list -> ID COLON TYPE error error SEMI error','case_list',7,'p_case_list_error','cool_parser.py',245), + ('case_list -> error COLON error ACTION expr SEMI error','case_list',7,'p_case_list_error','cool_parser.py',246), + ('case_list -> error COLON TYPE ACTION error SEMI error','case_list',7,'p_case_list_error','cool_parser.py',247), + ('case_list -> error COLON error ACTION error SEMI error','case_list',7,'p_case_list_error','cool_parser.py',248), + ('funccall -> ID OPAR CPAR','funccall',3,'p_func_call','cool_parser.py',252), + ('funccall -> ID OPAR arg_list CPAR','funccall',4,'p_func_call','cool_parser.py',253), + ('funccall -> error OPAR CPAR','funccall',3,'p_func_call_error','cool_parser.py',260), + ('funccall -> ID OPAR error CPAR','funccall',4,'p_func_call_error','cool_parser.py',261), + ('funccall -> error OPAR arg_list CPAR','funccall',4,'p_func_call_error','cool_parser.py',262), + ('funccall -> error OPAR error CPAR','funccall',4,'p_func_call_error','cool_parser.py',263), + ('arg_list -> expr','arg_list',1,'p_arg_list','cool_parser.py',267), + ('arg_list -> expr COMMA arg_list','arg_list',3,'p_arg_list','cool_parser.py',268), + ('arg_list -> error','arg_list',1,'p_arg_list_error','cool_parser.py',275), + ('arg_list -> error COMMA arg_list','arg_list',3,'p_arg_list_error','cool_parser.py',276), + ('expr -> ID ASSIGN expr','expr',3,'p_expr','cool_parser.py',280), + ('expr -> operat','expr',1,'p_expr','cool_parser.py',281), + ('expr -> ID ASSIGN error','expr',3,'p_expr_error','cool_parser.py',288), + ('expr -> error ASSIGN expr','expr',3,'p_expr_error','cool_parser.py',289), + ('operat -> operat LESSEQUAL operat','operat',3,'p_comp','cool_parser.py',293), + ('operat -> operat LESS operat','operat',3,'p_comp','cool_parser.py',294), + ('operat -> operat EQUAL operat','operat',3,'p_comp','cool_parser.py',295), + ('operat -> error LESSEQUAL operat','operat',3,'p_comp_error','cool_parser.py',304), + ('operat -> error LESSEQUAL error','operat',3,'p_comp_error','cool_parser.py',305), + ('operat -> operat LESSEQUAL error','operat',3,'p_comp_error','cool_parser.py',306), + ('operat -> error LESS operat','operat',3,'p_comp_error','cool_parser.py',307), + ('operat -> error LESS error','operat',3,'p_comp_error','cool_parser.py',308), + ('operat -> operat LESS error','operat',3,'p_comp_error','cool_parser.py',309), + ('operat -> error EQUAL operat','operat',3,'p_comp_error','cool_parser.py',310), + ('operat -> error EQUAL error','operat',3,'p_comp_error','cool_parser.py',311), + ('operat -> operat EQUAL error','operat',3,'p_comp_error','cool_parser.py',312), + ('operat -> operat PLUS operat','operat',3,'p_arith','cool_parser.py',316), + ('operat -> operat MINUS operat','operat',3,'p_arith','cool_parser.py',317), + ('operat -> operat STAR operat','operat',3,'p_arith','cool_parser.py',318), + ('operat -> operat DIV operat','operat',3,'p_arith','cool_parser.py',319), + ('operat -> operat PLUS error','operat',3,'p_operat_error','cool_parser.py',330), + ('operat -> error PLUS error','operat',3,'p_operat_error','cool_parser.py',331), + ('operat -> error PLUS operat','operat',3,'p_operat_error','cool_parser.py',332), + ('operat -> error MINUS operat','operat',3,'p_operat_error','cool_parser.py',333), + ('operat -> error MINUS error','operat',3,'p_operat_error','cool_parser.py',334), + ('operat -> operat MINUS error','operat',3,'p_operat_error','cool_parser.py',335), + ('operat -> operat STAR error','operat',3,'p_operat_error','cool_parser.py',336), + ('operat -> error STAR error','operat',3,'p_operat_error','cool_parser.py',337), + ('operat -> error STAR operat','operat',3,'p_operat_error','cool_parser.py',338), + ('operat -> operat DIV error','operat',3,'p_operat_error','cool_parser.py',339), + ('operat -> error DIV error','operat',3,'p_operat_error','cool_parser.py',340), + ('operat -> error DIV operat','operat',3,'p_operat_error','cool_parser.py',341), + ('operat -> baseop','operat',1,'p_base_operat','cool_parser.py',345), + ('baseop -> subatom AT TYPE DOT funccall','baseop',5,'p_static_call','cool_parser.py',349), + ('baseop -> error AT TYPE DOT funccall','baseop',5,'p_static_call_error','cool_parser.py',353), + ('baseop -> subatom AT error DOT funccall','baseop',5,'p_static_call_error','cool_parser.py',354), + ('baseop -> subatom AT TYPE DOT error','baseop',5,'p_static_call_error','cool_parser.py',355), + ('baseop -> error AT error DOT funccall','baseop',5,'p_static_call_error','cool_parser.py',356), + ('baseop -> error AT TYPE DOT error','baseop',5,'p_static_call_error','cool_parser.py',357), + ('baseop -> subatom AT error DOT error','baseop',5,'p_static_call_error','cool_parser.py',358), + ('baseop -> error AT error DOT error','baseop',5,'p_static_call_error','cool_parser.py',359), + ('baseop -> subatom','baseop',1,'p_sub_atom','cool_parser.py',363), + ('subatom -> OPAR expr CPAR','subatom',3,'p_parent_expr','cool_parser.py',367), + ('subatom -> error expr CPAR','subatom',3,'p_parent_expr_error','cool_parser.py',371), + ('subatom -> OPAR expr error','subatom',3,'p_parent_expr_error','cool_parser.py',372), + ('subatom -> subatom DOT funccall','subatom',3,'p_dynamic_call','cool_parser.py',376), + ('subatom -> subatom DOT error','subatom',3,'p_dynamic_call_error','cool_parser.py',380), + ('subatom -> error DOT funccall','subatom',3,'p_dynamic_call_error','cool_parser.py',381), + ('subatom -> error DOT error','subatom',3,'p_dynamic_call_error','cool_parser.py',382), + ('subatom -> funccall','subatom',1,'p_member_call','cool_parser.py',386), + ('subatom -> INT_COMPLEMENT baseop','subatom',2,'p_unary_operations','cool_parser.py',390), + ('subatom -> NOT operat','subatom',2,'p_unary_operations','cool_parser.py',391), + ('subatom -> ISVOID baseop','subatom',2,'p_unary_operations','cool_parser.py',392), + ('subatom -> NOT error','subatom',2,'p_unary_operations_error','cool_parser.py',401), + ('subatom -> IF expr THEN expr ELSE expr FI','subatom',7,'p_complex_sub_atom','cool_parser.py',405), + ('subatom -> WHILE expr LOOP expr POOL','subatom',5,'p_complex_sub_atom','cool_parser.py',406), + ('subatom -> LET let_list IN expr','subatom',4,'p_complex_sub_atom','cool_parser.py',407), + ('subatom -> CASE expr OF case_list ESAC','subatom',5,'p_complex_sub_atom','cool_parser.py',408), + ('subatom -> atom','subatom',1,'p_atom','cool_parser.py',422), + ('atom -> NEW TYPE','atom',2,'p_new','cool_parser.py',426), + ('atom -> NEW error','atom',2,'p_new_error','cool_parser.py',430), + ('atom -> OCURL expr_block CCURL','atom',3,'p_atom_expr_block','cool_parser.py',434), + ('atom -> OCURL error CCURL','atom',3,'p_atom_expr_block_error','cool_parser.py',438), + ('atom -> ID','atom',1,'p_atom_id','cool_parser.py',442), + ('atom -> INTEGER','atom',1,'p_atom_integer','cool_parser.py',446), + ('atom -> STRING','atom',1,'p_atom_string','cool_parser.py',450), + ('atom -> BOOL','atom',1,'p_atom_bool','cool_parser.py',454), +] diff --git a/src/engine/semantic_errors.py b/src/engine/semantic_errors.py new file mode 100644 index 00000000..e3e2e157 --- /dev/null +++ b/src/engine/semantic_errors.py @@ -0,0 +1,14 @@ +ERROR_ON_LN_COL = '(%d, %d) - ' +WRONG_SIGNATURE = 'Method "%s" of "%s" already defined in "%s" with a different signature.' +SELF_IS_READONLY = 'Variable "self" is read-only.' +LOCAL_ALREADY_DEFINED = 'Variable "%s" is already defined in method "%s".' +INCOMPATIBLE_TYPES = 'Cannot convert "%s" into "%s".' +VARIABLE_NOT_DEFINED = 'Variable "%s" is not defined in "%s".' +INVALID_OPERATION = 'Operation is not defined between "%s" and "%s".' +CYCLIC_HERITAGE = 'Type "%s" froms a cyclic heritage chain' +INFERENCE_ON = 'Ln %d, Col %d: ' +INF_ATTR = 'On class "%s", attribute "%s": type "%s"' +INF_PARAM = 'On method "%s" of class "%s", param "%s": type "%s"' +INF_RETRN = 'Return of method "%s" in class "%s", type "%s"' +INF_VAR = 'Varible "%s", type "%s"' +NON_TYPE_ARGUMENTS = 'Non-%s arguments: %s %s %s' \ No newline at end of file diff --git a/src/engine/visitors/__init__.py b/src/engine/visitors/__init__.py new file mode 100644 index 00000000..bb8960c8 --- /dev/null +++ b/src/engine/visitors/__init__.py @@ -0,0 +1,5 @@ +from .builder import Builder +from .checker import Checker +from .collector import Collector +from .format import Format +from .inferer import Inferer \ No newline at end of file diff --git a/src/engine/visitors/builder.py b/src/engine/visitors/builder.py new file mode 100644 index 00000000..29bf594f --- /dev/null +++ b/src/engine/visitors/builder.py @@ -0,0 +1,117 @@ +from engine.cp import ErrorType, SelfType, SemanticError, visitor +from engine.parser import AttrDeclarationNode, FuncDeclarationNode, ProgramNode, ClassDeclarationNode +from engine.semantic_errors import ERROR_ON_LN_COL + +class Builder: + def __init__(self, context, errors = []): + self.context = context + self.current_type = None + self.errors = errors + + #Construyendo tipos Build-In + + self.object_type = self.context.get_type('Object') + + self.io_type = self.context.get_type('IO') + self.io_type.set_parent(self.object_type) + + self.int_type = self.context.get_type('Int') + self.int_type.set_parent(self.object_type) + self.int_type.sealed = True + + self.string_type = self.context.get_type('String') + self.string_type.set_parent(self.object_type) + self.string_type.sealed = True + + self.bool_type = self.context.get_type('Bool') + self.bool_type.set_parent(self.object_type) + self.bool_type.sealed = True + + self.object_type.define_method('abort', [], [], self.object_type) + self.object_type.define_method('type_name', [], [], self.string_type) + self.object_type.define_method('copy', [], [], SelfType()) + + self.io_type.define_method('out_string', ['x'], [self.string_type], SelfType()) + self.io_type.define_method('out_int', ['x'], [self.int_type], SelfType()) + self.io_type.define_method('in_string', [], [], self.string_type) + self.io_type.define_method('in_int', [], [], self.int_type) + + self.string_type.define_method('length', [], [], self.int_type) + self.string_type.define_method('concat', ['s'], [self.string_type], self.string_type) + self.string_type.define_method('substr', ['i', 'l'], [self.int_type, self.int_type], self.string_type) + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + for class_def in node.declarations: + self.visit(class_def) + try: + self.context.get_type('Main').get_method('main') + except SemanticError: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "SemanticError: Class Main and feature main needed") + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + self.current_type = self.context.get_type(node.id.lex) + + parent = node.parent + if parent: + parent_type = None + try: + parent_type = self.context.get_type(parent.lex) + self.current_type.set_parent(parent_type) + except SemanticError as se: + if self.current_type and parent_type != None and parent_type.sealed: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "SemanticError: " + se.text) + else: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "TypeError: " + se.text) + self.current_type.set_parent(self.object_type) + else: + self.current_type.set_parent(self.object_type) + + for feature in node.features: + self.visit(feature) + + @visitor.when(AttrDeclarationNode) + def visit(self, node): + try: + attr_type = self.context.get_type(node.type.lex) + except SemanticError as se: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "TypeError: " + se.text) + attr_type = ErrorType() + + try: + self.current_type.define_attribute(node.id.lex, attr_type) + except SemanticError as se: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "SemanticError: " + se.text) + + @visitor.when(FuncDeclarationNode) + def visit(self, node): + arg_names, arg_types = [], [] + for ids, types in node.params: + try: + arg_type = self.context.get_type(types.lex) + except SemanticError as se: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "TypeError: " + se.text) + arg_type = ErrorType() + else: + if isinstance(arg_type, SelfType): + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "SemanticError: " + f'Type "{arg_type.name}" can not be used as a parameter type') + arg_type = ErrorType() + + arg_names.append(ids.lex) + arg_types.append(arg_type) + + try: + ret_type = self.context.get_type(node.type.lex) + except SemanticError as se: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "TypeError: " + se.text) + ret_type = ErrorType() + + try: + self.current_type.define_method(node.id.lex, arg_names, arg_types, ret_type) + except SemanticError as se: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "SemanticError: " + se.text) \ No newline at end of file diff --git a/src/engine/visitors/checker.py b/src/engine/visitors/checker.py new file mode 100644 index 00000000..261a8300 --- /dev/null +++ b/src/engine/visitors/checker.py @@ -0,0 +1,468 @@ +from engine.cp import visitor, ErrorType, SelfType, SemanticError, Scope +from engine.parser import ProgramNode, ClassDeclarationNode, AttrDeclarationNode, FuncDeclarationNode +from engine.parser import IfThenElseNode, WhileLoopNode, BlockNode, LetInNode, CaseOfNode +from engine.parser import AssignNode, UnaryNode, BinaryNode, LessEqualNode, LessNode, EqualNode, ArithmeticNode +from engine.parser import NotNode, IsVoidNode, ComplementNode, FunctionCallNode, MemberCallNode, NewNode, AtomicNode +from engine.parser import IntegerNode, IdNode, StringNode, BoolNode +from engine.semantic_errors import NON_TYPE_ARGUMENTS, ERROR_ON_LN_COL, WRONG_SIGNATURE, SELF_IS_READONLY, LOCAL_ALREADY_DEFINED, INCOMPATIBLE_TYPES, VARIABLE_NOT_DEFINED, INVALID_OPERATION, CYCLIC_HERITAGE + + +class Checker: + def __init__(self, context, errors=[]): + self.context = context + self.current_type = None + self.current_method = None + self.errors = errors + + # Tipos Built-in + self.object_type = self.context.get_type('Object') + self.io_type = self.context.get_type('IO') + self.int_type = self.context.get_type('Int') + self.string_type = self.context.get_type('String') + self.bool_type = self.context.get_type('Bool') + + @visitor.on('node') + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node, scope=None): + scope = Scope() + for d in node.declarations: + self.visit(d, scope.create_child()) + return scope + + @visitor.when(ClassDeclarationNode) + def visit(self, node, scope): + self.current_type = self.context.get_type(node.id.lex) + + attrs = [] + self.current_type.parent = ( + self.current_type.parent + if self.current_type.parent + else self.context.get_type('Object')) + parent = self.current_type.parent + self.context.inheritance[self.current_type.name] = parent.name + + while parent: + + if parent == self.current_type: + self.errors.append(ERROR_ON_LN_COL % ( + node.line, node.column) + "SemanticError: " + CYCLIC_HERITAGE % (parent.name)) + self.current_type.parent = self.object_type + break + attrs += parent.attributes + parent = parent.parent + + for a in self.current_type.attributes + attrs: + if a.name == 'self': + line, column = [(attrib.line, attrib.column) for attrib in node.features if type( + attrib) is AttrDeclarationNode and attrib.id.lex == 'self'][0] + self.errors.append(ERROR_ON_LN_COL % ( + line, column) + "SemanticError: " + "Incorrect use of self in attribute declaration") + + scope.define_variable(a.name, a.type) + + for f in node.features: + self.visit(f, scope.create_child()) + + @visitor.when(AttrDeclarationNode) + def visit(self, node, scope): + expr = node.expression + if expr: + scope_child: Scope = scope.create_child() + scope_child.define_variable('self', self.current_type) + self.visit(expr, scope_child) + expr_type = expr.static_type + + attr = self.current_type.get_attribute(node.id.lex) + node_type = attr.type + node_type = self.current_type if isinstance( + node_type, SelfType) else node_type + if not expr_type.conforms_to(node_type): + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + + "TypeError: " + INCOMPATIBLE_TYPES % (expr_type.name, node_type.name)) + + @visitor.when(FuncDeclarationNode) + def visit(self, node, scope): + self.current_method = self.current_type.get_method(node.id.lex) + + # check ilegal redefined func + parent = self.current_type.parent + if parent: + try: + parent_method = parent.get_method(node.id.lex) + except SemanticError: + pass + else: + if parent_method.param_types != self.current_method.param_types or parent_method.return_type != self.current_method.return_type: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "SemanticError: " + + WRONG_SIGNATURE % (self.current_method.name, self.current_type.name, parent.name)) + + scope.define_variable('self', self.current_type) + + for pname, ptype in zip(self.current_method.param_names, self.current_method.param_types): + if pname == 'self': + self.errors.append(ERROR_ON_LN_COL % ( + node.line, node.column) + "SemanticError: " + "Wrong use of self as method parameter") + + try: + scope.define_variable(pname, ptype) + except SemanticError: + self.errors.append(ERROR_ON_LN_COL % ( + node.line, node.column) + "SemanticError: " + f"Parameter {pname} can only be used once") + + body = node.body + self.visit(body, scope.create_child()) + + body_type = body.static_type + return_type = self.current_type if isinstance( + self.current_method.return_type, SelfType) else self.current_method.return_type + + if not body_type.conforms_to(return_type): + self.errors.append(ERROR_ON_LN_COL % (body.line, body.column) + + "TypeError: " + INCOMPATIBLE_TYPES % (body_type.name, return_type.name)) + + @visitor.when(IfThenElseNode) + def visit(self, node, scope): + condition = node.condition + self.visit(condition, scope.create_child()) + + condition_type = condition.static_type + if not condition_type.conforms_to(self.bool_type): + self.errors.append(ERROR_ON_LN_COL % (condition.line, condition.column) + + "TypeError: " + INCOMPATIBLE_TYPES % (condition_type.name, self.bool_type.name)) + + self.visit(node.if_body, scope.create_child()) + self.visit(node.else_body, scope.create_child()) + + if_type = node.if_body.static_type + else_type = node.else_body.static_type + node.static_type = if_type.type_union(else_type) + + @visitor.when(WhileLoopNode) + def visit(self, node, scope): + condition = node.condition + self.visit(condition, scope.create_child()) + + condition_type = condition.static_type + if not condition_type.conforms_to(self.bool_type): + self.errors.append(ERROR_ON_LN_COL % (condition.line, condition.column) + + "TypeError: " + INCOMPATIBLE_TYPES % (condition_type.name, self.bool_type.name)) + + self.visit(node.body, scope.create_child()) + + node.static_type = self.object_type + + @visitor.when(BlockNode) + def visit(self, node, scope): + for expr in node.expressions: + self.visit(expr, scope.create_child()) + + node.static_type = node.expressions[-1].static_type + + @visitor.when(LetInNode) + def visit(self, node, scope): + for idx, typex, expr in node.let_body: + try: + node_type = self.context.get_type(typex.lex) + except SemanticError as ex: + self.errors.append(ERROR_ON_LN_COL % ( + typex.line, typex.column) + "TypeError: " + ex.text) + node_type = ErrorType() + + id_type = self.current_type if isinstance( + node_type, SelfType) else node_type + + if idx.lex == 'self': + self.errors.append(ERROR_ON_LN_COL % (expr.line, expr.column) + + "SemanticError: " + "'self' cannot be bound in a 'let' expression.") + + child = scope.create_child() + + if expr: + self.visit(expr, child) + expr_type = expr.static_type + if not expr_type.conforms_to(id_type): + self.errors.append(ERROR_ON_LN_COL % ( + expr.line, expr.column) + "TypeError: " + INCOMPATIBLE_TYPES % (expr_type.name, id_type.name)) + + try: + scope.define_variable(idx.lex, id_type, True) + except SemanticError as e: + self.errors.append(ERROR_ON_LN_COL % ( + idx.line, idx.column) + "SemanticError: " + e.text) + + self.visit(node.in_body, scope.create_child()) + + node.static_type = node.in_body.static_type + + @visitor.when(CaseOfNode) + def visit(self, node, scope): + self.visit(node.expression, scope.create_child()) + + node.static_type = None + + case_types = [] + + for idx, typex, expr in node.branches: + try: + node_type = self.context.get_type(typex.lex) + if node_type in case_types: + self.errors.append(ERROR_ON_LN_COL % ( + typex.line, typex.column) + "SemanticError: " + f"Duplicate Branch {node_type} in case declaration") + else: + case_types.append(node_type) + except SemanticError as ex: + self.errors.append(ERROR_ON_LN_COL % ( + typex.line, typex.column) + "TypeError: " + ex.text) + node_type = ErrorType() + else: + if isinstance(node_type, SelfType): + self.errors.append(ERROR_ON_LN_COL % ( + typex.line, typex.column) + "SemanticError: " + f'Type "{node_type.name}" can not be used as case type') + node_type = ErrorType() + + id_type = node_type + + child_scope = scope.create_child() + child_scope.define_variable(idx.lex, id_type) + self.visit(expr, child_scope) + expr_type = expr.static_type + + node.static_type = node.static_type.type_union( + expr_type) if node.static_type else expr_type + + @visitor.when(AssignNode) + def visit(self, node, scope): + expression = node.expression + node_type = ErrorType() + + if scope.is_defined(node.id.lex): + var = scope.find_variable(node.id.lex) + node_type = var.type + + if var.name == 'self': + self.errors.append(ERROR_ON_LN_COL % ( + node.line, node.column) + "SemanticError: " + SELF_IS_READONLY) + else: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "NameError: " + + VARIABLE_NOT_DEFINED % (node.id.lex, self.current_method.name)) + + self.visit(expression, scope.create_child()) + expr_type = expression.static_type + + if not expr_type.conforms_to(node_type): + self.errors.append(ERROR_ON_LN_COL % (expression.line, expression.column) + + "TypeError: " + INCOMPATIBLE_TYPES % (expr_type.name, node_type.name)) + + node.static_type = expr_type + + @visitor.when(NotNode) + def visit(self, node, scope): + expression = node.expression + self.visit(expression, scope.create_child()) + + expr_type = expression.static_type + if not expr_type.conforms_to(self.bool_type): + self.errors.append(ERROR_ON_LN_COL % (expression.line, expression.column) + + "TypeError: " + INCOMPATIBLE_TYPES % (expr_type.name, self.bool_type.name)) + + node.static_type = self.bool_type + + @visitor.when(LessEqualNode) + def visit(self, node, scope): + self.visit(node.left, scope.create_child()) + left_type = node.left.static_type + + self.visit(node.right, scope.create_child()) + right_type = node.right.static_type + + if not left_type.conforms_to(self.int_type) or not right_type.conforms_to(self.int_type): + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + + "TypeError: " + INVALID_OPERATION % (right_type.name, self.int_type.name)) + + node.static_type = self.bool_type + + @visitor.when(LessNode) + def visit(self, node, scope): + self.visit(node.left, scope.create_child()) + left_type = node.left.static_type + + self.visit(node.right, scope.create_child()) + right_type = node.right.static_type + + if not left_type.conforms_to(self.int_type) or not right_type.conforms_to(self.int_type): + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + + "TypeError: " + INVALID_OPERATION % (right_type.name, self.int_type.name)) + + node.static_type = self.bool_type + + @visitor.when(EqualNode) + def visit(self, node, scope): + self.visit(node.left, scope.create_child()) + left_type = node.left.static_type + + self.visit(node.right, scope.create_child()) + right_type = node.right.static_type + + if left_type.conforms_to(self.int_type) ^ right_type.conforms_to(self.int_type): + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + + "TypeError: " + INVALID_OPERATION % (left_type.name, right_type.name)) + elif left_type.conforms_to(self.string_type) ^ right_type.conforms_to(self.string_type): + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + + "TypeError: " + INVALID_OPERATION % (left_type.name, right_type.name)) + elif left_type.conforms_to(self.bool_type) ^ right_type.conforms_to(self.bool_type): + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + + "TypeError: " + INVALID_OPERATION % (left_type.name, right_type.name)) + + node.static_type = self.bool_type + + @visitor.when(ArithmeticNode) + def visit(self, node, scope): + self.visit(node.left, scope.create_child()) + left_type = node.left.static_type + + self.visit(node.right, scope.create_child()) + right_type = node.right.static_type + + if not left_type.conforms_to(self.int_type) or not right_type.conforms_to(self.int_type): + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + + "TypeError: " + INVALID_OPERATION % (left_type.name, right_type.name)) + + node.static_type = self.int_type + + @visitor.when(IsVoidNode) + def visit(self, node, scope): + self.visit(node.expression, scope.create_child()) + + node.static_type = self.bool_type + + @visitor.when(ComplementNode) + def visit(self, node, scope): + expression = node.expression + self.visit(expression, scope.create_child()) + + expr_type = expression.static_type + if not expr_type.conforms_to(self.int_type): + self.errors.append(ERROR_ON_LN_COL % (expression.line, expression.column) + + "TypeError: " + INCOMPATIBLE_TYPES % (expr_type.name, self.int_type.name)) + + node.static_type = self.int_type + + @visitor.when(FunctionCallNode) + def visit(self, node, scope): + self.visit(node.obj, scope.create_child()) + obj_type = node.obj.static_type + + try: + if node.type: + try: + node_type = self.context.get_type(node.type.lex) + except SemanticError as ex: + self.errors.append(ERROR_ON_LN_COL % ( + node.type.line, node.type.column) + "TypeError: " + ex.text) + node_type = ErrorType() + return + else: + if isinstance(node_type, SelfType): + self.errors.append(ERROR_ON_LN_COL % (node.type.line, node.type.column) + + "SemanticError: " + f'Type "{node_type}" cannot be used as type dispatch') + node_type = ErrorType() + + if not obj_type.conforms_to(node_type): + self.errors.append(ERROR_ON_LN_COL % (node.obj.line, node.obj.column) + + "TypeError: " + INCOMPATIBLE_TYPES % (obj_type.name, node_type.name)) + + obj_type = node_type + + obj_method = obj_type.get_method(node.id.lex) + + node_type = obj_type if isinstance( + obj_method.return_type, SelfType) else obj_method.return_type + except SemanticError as ex: + self.errors.append(ERROR_ON_LN_COL % ( + node.line, node.column) + "AttributeError: " + ex.text) + node_type = ErrorType() + obj_method = None + + else: + if obj_method and len(node.args) == len(obj_method.param_types): + for arg, param_type in zip(node.args, obj_method.param_types): + self.visit(arg, scope.create_child()) + arg_type = arg.static_type + + if not arg_type.conforms_to(param_type): + self.errors.append(ERROR_ON_LN_COL % ( + arg.line, arg.column) + "TypeError: " + INCOMPATIBLE_TYPES % (arg_type.name, param_type.name)) + else: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + + "SemanticError: " + f'Method "{node.id.lex}" can not be dispatched') + + node.static_type = node_type + + @visitor.when(MemberCallNode) + def visit(self, node, scope): + obj_type = self.current_type + + try: + obj_method = obj_type.get_method(node.id.lex) + + node_type = obj_type if isinstance( + obj_method.return_type, SelfType) else obj_method.return_type + except SemanticError as ex: + self.errors.append(ERROR_ON_LN_COL % ( + node.line, node.column) + "AttributeError: " + ex.text) + node_type = ErrorType() + obj_method = None + + else: + if obj_method and len(node.args) == len(obj_method.param_types): + for arg, param_type in zip(node.args, obj_method.param_types): + self.visit(arg, scope.create_child()) + arg_type = arg.static_type + + if not arg_type.conforms_to(param_type): + self.errors.append(ERROR_ON_LN_COL % ( + arg.line, arg.column) + "TypeError: " + INCOMPATIBLE_TYPES % (arg_type.name, param_type.name)) + else: + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + + "SemanticError: " + f'Method "{node.id.lex}" can not be dispatched') + + node.static_type = node_type + + @visitor.when(NewNode) + def visit(self, node, scope): + try: + node_type = self.context.get_type(node.type.lex) + except SemanticError as ex: + self.errors.append(ERROR_ON_LN_COL % ( + node.line, node.column) + "TypeError: " + ex.text) + node_type = ErrorType() + + node.static_type = node_type + + @visitor.when(IntegerNode) + def visit(self, node, scope): + node.static_type = self.int_type + + @visitor.when(StringNode) + def visit(self, node, scope): + node.static_type = self.string_type + + @visitor.when(IdNode) + def visit(self, node, scope): + if scope.is_defined(node.token.lex): + var = scope.find_variable(node.token.lex) + node_type = var.type + else: + + self.errors.append(ERROR_ON_LN_COL % (node.line, node.column) + "NameError: " + + VARIABLE_NOT_DEFINED % (node.token.lex, self.current_method.name if self.current_method else '')) + node_type = ErrorType() + + node.static_type = node_type + + @visitor.when(BoolNode) + def visit(self, node, scope): + node.static_type = self.bool_type diff --git a/src/engine/visitors/collector.py b/src/engine/visitors/collector.py new file mode 100644 index 00000000..33fb333e --- /dev/null +++ b/src/engine/visitors/collector.py @@ -0,0 +1,62 @@ +from engine.cp import SemanticError, visitor, Context, SelfType +from engine.parser import ProgramNode, ClassDeclarationNode +from engine.semantic_errors import ERROR_ON_LN_COL, CYCLIC_HERITAGE + + +class Collector: + def __init__(self, errors=[]): + self.context = Context() + self.errors = errors + self.parents = {} + + # Tipos especiales + self.context.add_type(SelfType()) + + # Tipos Buit-In + self.context.create_type('Object', builtin=True) + self.context.create_type('IO', builtin=True) + self.context.create_type('Int', builtin=True) + self.context.create_type('String', builtin=True) + self.context.create_type('Bool', builtin=True) + + self.parents['Object'] = None + self.parents['IO'] = 'Object' + self.parents['Int'] = 'Object' + self.parents['String'] = 'Object' + self.parents['Bool'] = 'Object' + + def ciclic_heritage(self, name, parent): + if parent is None: + return False + if name == parent: + return True + return self.ciclic_heritage(name, self.parents[parent]) + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + for class_def in node.declarations: + self.visit(class_def) + + if not len(self.errors): + for declaration in node.declarations: + if declaration.id.lex not in self.parents.keys(): + self.parents[declaration.id.lex] = 'Object' if declaration.parent == None else declaration.parent.lex + if declaration.parent != None and declaration.parent.lex in self.parents.keys() and self.ciclic_heritage(declaration.id.lex, declaration.parent.lex): + self.errors.append(ERROR_ON_LN_COL % ( + declaration.line, declaration.column) + "SemanticError: " + CYCLIC_HERITAGE % (declaration.id.lex)) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + try: + self.context.create_type(node.id.lex) + if(node.parent): + self.parents[node.id.lex] = node.parent.lex + else: + self.parents[node.id.lex] = 'Object' + except SemanticError as se: + self.errors.append(ERROR_ON_LN_COL % ( + node.line, node.column) + "SemanticError: " + se.text) diff --git a/src/engine/visitors/format.py b/src/engine/visitors/format.py new file mode 100644 index 00000000..d96ff723 --- /dev/null +++ b/src/engine/visitors/format.py @@ -0,0 +1,119 @@ +from engine.cp import visitor +from engine.parser import ProgramNode, ClassDeclarationNode, AttrDeclarationNode, FuncDeclarationNode +from engine.parser import IfThenElseNode, WhileLoopNode, BlockNode, LetInNode, CaseOfNode +from engine.parser import AssignNode, UnaryNode, BinaryNode +from engine.parser import FunctionCallNode, MemberCallNode, NewNode, AtomicNode + +class Format: + @visitor.on('node') + def visit(self, node, tabs): + pass + + @visitor.when(ProgramNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__ProgramNode [ ... ]' + statements = '\n'.join(self.visit(child, tabs + 1) for child in node.declarations) + return f'{ans}\n{statements}' + + @visitor.when(ClassDeclarationNode) + def visit(self, node, tabs=0): + parent = '' if node.parent is None else f"inherits {node.parent.lex}" + ans = '\t' * tabs + f'\\__ClassDeclarationNode: class {node.id.lex} {parent} {{ ... }}' + features = '\n'.join(self.visit(child, tabs + 1) for child in node.features) + return f'{ans}\n{features}' + + @visitor.when(AttrDeclarationNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__AttrDeclarationNode: {node.id.lex}: {node.type.lex}' + (' <- ' if node.expression else '') + ';' + expr = self.visit(node.expression, tabs + 1) if node.expression else None + return f'{ans}' + (f'\n{expr}' if expr else '') + + @visitor.when(FuncDeclarationNode) + def visit(self, node, tabs=0): + params = ', '.join(': '.join(tok.lex for tok in param) for param in node.params) + ans = '\t' * tabs + f'\\__FuncDeclarationNode: {node.id.lex}({params}): {node.type.lex} {{ }}' + body = self.visit(node.body, tabs + 1) + return f'{ans}\n{body}' + + @visitor.when(IfThenElseNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\_IfThenElseNode: if then else fi' + cond = self.visit(node.condition, tabs + 1) + if_body = self.visit(node.if_body, tabs + 1) + else_body = self.visit(node.else_body, tabs + 1) + return f'{ans}\n{cond}\n{if_body}\n{else_body}' + + @visitor.when(WhileLoopNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\_WhileNode: while loop pool' + cond = self.visit(node.condition, tabs + 1) + body = self.visit(node.body, tabs + 1) + return f'{ans}\n{cond}\n{body}' + + @visitor.when(BlockNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\_BlockNode: {{ ; ... ; }}' + expressions = '\n'.join(self.visit(expr, tabs + 1) for expr in node.expressions) + return f'{ans}\n{expressions}' + + @visitor.when(LetInNode) + def visit(self, node, tabs=0): + let_body = ', '.join(f'{idx.lex}: {typex.lex}' + (' <- ' if expr else '') for idx, typex, expr in node.let_body) + ans = '\t' * tabs + f'\\_LetInNode: let {let_body} in ' + lets = '\n'.join(self.visit(expr, tabs + 1) for _, _, expr in node.let_body if expr) + if node.in_body is None: + return f'{ans}\n{lets}' + else: + body = self.visit(node.in_body, tabs + 1) + return f'{ans}\n{lets}\n{body}' + # @visitor.when(Let) + # def visit(self, node, tabs=0): + + @visitor.when(CaseOfNode) + def visit(self, node, tabs=0): + case_body = ' '.join(f'{idx.lex}: {typex.lex} => ;' for idx, typex, expr in node.branches) + ans = '\t' * tabs + f'\\_CaseOfNode: case of {case_body} esac' + expression = self.visit(node.expression, tabs + 1) + body = '\n'.join(self.visit(expr, tabs + 1) for _, _, expr in node.branches) + return f'{ans}\n{expression}\n{body}' + + @visitor.when(AssignNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\_AssingNode: {node.id.lex} <- ' + expr = self.visit(node.expression, tabs + 1) + return f'{ans}\n{expr}' + + @visitor.when(UnaryNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__{node.__class__.__name__} ' + expression = self.visit(node.expression, tabs + 1) + return f'{ans}\n{expression}' + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__ {node.__class__.__name__} ' + left = self.visit(node.left, tabs + 1) + right = self.visit(node.right, tabs + 1) + return f'{ans}\n{left}\n{right}' + + @visitor.when(FunctionCallNode) + def visit(self, node, tabs=0): + obj = self.visit(node.obj, tabs + 1) + typex = f'@{node.type.lex}' if node.type else '' + ans = '\t' * tabs + f'\\__FunctionCallNode: {typex}.{node.id.lex}(, ..., )' + args = '\n'.join(self.visit(arg, tabs + 1) for arg in node.args) + return f'{ans}\n{obj}\n{args}' + + @visitor.when(MemberCallNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__MemberCallNode: {node.id.lex}(, ..., )' + args = '\n'.join(self.visit(arg, tabs + 1) for arg in node.args) + return f'{ans}\n{args}' + + @visitor.when(NewNode) + def visit(self, node, tabs=0): + return '\t' * tabs + f'\\__ NewNode: new {node.type.lex}' + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + return '\t' * tabs + f'\\__ {node.__class__.__name__}: {node.token.lex}' diff --git a/src/engine/visitors/inferer.py b/src/engine/visitors/inferer.py new file mode 100644 index 00000000..ed509dad --- /dev/null +++ b/src/engine/visitors/inferer.py @@ -0,0 +1,335 @@ +from engine.cp import visitor, ErrorType, SelfType, SemanticError +from engine.parser import ProgramNode, ClassDeclarationNode, AttrDeclarationNode, FuncDeclarationNode +from engine.parser import IfThenElseNode, WhileLoopNode, BlockNode, LetInNode, CaseOfNode +from engine.parser import AssignNode, UnaryNode, BinaryNode, LessEqualNode, LessNode, EqualNode, ArithmeticNode +from engine.parser import NotNode, IsVoidNode, ComplementNode, FunctionCallNode, MemberCallNode, NewNode, AtomicNode +from engine.parser import IntegerNode, IdNode, StringNode, BoolNode +from engine.semantic_errors import ERROR_ON_LN_COL, INFERENCE_ON, INF_ATTR, INF_PARAM, INF_RETRN, INF_VAR + +class Inferer: + def __init__(self, context, errors=[], inferences=[]): + self.context = context + self.current_type = None + self.current_method = None + self.errors = errors + self.inferences = inferences + + # search built-in types + self.object_type = self.context.get_type('Object') + self.io_type = self.context.get_type('IO') + self.int_type = self.context.get_type('Int') + self.string_type = self.context.get_type('String') + self.bool_type = self.context.get_type('Bool') + + @visitor.on('node') + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node, scope): + self.changed = False + + for declaration, child_scope in zip(node.declarations, scope.children): + self.visit(declaration, child_scope) + + return self.changed + + @visitor.when(ClassDeclarationNode) + def visit(self, node, scope): + self.current_type = self.context.get_type(node.id.lex) + + for feature, child_scope in zip(node.features, scope.children): + self.visit(feature, child_scope) + + for attr, var in zip(self.current_type.attributes, scope.locals): + val, error = var.infer_type() + if val: + if error: + self.errors.append("On " + node.id.lex + " " + ERROR_ON_LN_COL % (node.line, node.column) + error) + self.changed = True + attr.type = var.type + self.inferences.append(INF_ATTR % (self.current_type.name, attr.name, var.type.name)) + + @visitor.when(AttrDeclarationNode) + def visit(self, node, scope): + expression = node.expression + if expression: + attr = self.current_type.get_attribute(node.id.lex) + + self.visit(expression, scope.children[0], attr.type) + expr_type = expression.static_type + + var = scope.find_variable(node.id.lex) + var.set_calls(expr_type) + val, error = var.infer_type() + if val: + if error: + self.errors.append("On " + node.id.lex + " " + ERROR_ON_LN_COL % (node.line, node.column) + error) + self.changed = True + attr.type = var.type + self.inferences.append(INF_ATTR % (self.current_type.name, attr.name, var.type.name)) + + @visitor.when(FuncDeclarationNode) + def visit(self, node, scope): + self.current_method = self.current_type.get_method(node.id.lex) + + return_type = self.current_method.return_type + self.visit(node.body, scope.children[0], self.current_type if isinstance(return_type, SelfType) else return_type) + + for i, var in enumerate(scope.locals[1:]): + val, error = var.infer_type() + if val: + if error: + self.errors.append("On " + node.id.lex + " " + ERROR_ON_LN_COL % (node.line, node.column) + error) + self.changed = True + self.current_method.param_types[i] = var.type + self.inferences.append(INF_PARAM % (self.current_method.name, self.current_type.name, var.name, var.type.name)) + + body_type = node.body.static_type + var = self.current_method.return_info + var.set_assigns(body_type) + val, error = var.infer_type() + if val: + if error: + self.errors.append("On " + node.id.lex + " " + ERROR_ON_LN_COL % (node.line, node.column) + error) + self.changed = True + self.current_method.return_type = var.type + self.inferences.append(INF_RETRN % (self.current_method.name, self.current_type.name, var.type.name)) + + @visitor.when(IfThenElseNode) + def visit(self, node, scope, expected_type=None): + # posible inferencia + self.visit(node.condition, scope.children[0], self.bool_type) + + self.visit(node.if_body, scope.children[1]) + self.visit(node.else_body, scope.children[2]) + + if_type = node.if_body.static_type + else_type = node.else_body.static_type + node.static_type = if_type.type_union(else_type) + + @visitor.when(WhileLoopNode) + def visit(self, node, scope, expected_type=None): + # posible inferencia + self.visit(node.condition, scope.children[0], self.bool_type) + + self.visit(node.body, scope.children[1]) + + node.static_type = self.object_type + + @visitor.when(BlockNode) + def visit(self, node, scope, expected_type=None): + for expr, child_scope in zip(node.expressions[:-1], scope.children[:-1]): + self.visit(expr, child_scope) + # posible inferencia + self.visit(node.expressions[-1], scope.children[-1], expected_type) + + node.static_type = node.expressions[-1].static_type + + @visitor.when(LetInNode) + def visit(self, node, scope, expected_type=None): + for (idx, typex, expr), child_scope, (i, var) in zip(node.let_body, scope.children[:-1], enumerate(scope.locals)): + if expr: + self.visit(expr, child_scope, var.type if var.infered else None) + expr_type = expr.static_type + + var.set_calls(expr_type) + val, error = var.infer_type() + if val: + if error: + self.errors.append("On " + node.id.lex + " " + ERROR_ON_LN_COL % (node.line, node.column) + error) + self.changed = True + typex.name = var.type.name + self.inferences.append(INFERENCE_ON % (idx.line, idx.column) + INF_VAR % (var.name, var.type.name)) + + self.visit(node.in_body, scope.children[-1], expected_type) + + for i, var in enumerate(scope.locals): + val, error = var.infer_type() + if val: + if error: + self.errors.append("On " + node.id.lex + " " + ERROR_ON_LN_COL % (node.line, node.column) + error) + self.changed = True + idx, typex, _ = node.let_body[i] + typex.name = var.type.name + self.inferences.append(INFERENCE_ON % (idx.line, idx.column) + INF_VAR % (var.name, var.type.name)) + + node.static_type = node.in_body.static_type + + @visitor.when(CaseOfNode) + def visit(self, node, scope, expected_type=None): + self.visit(node.expression, scope.children[0]) + + node.static_type = None + + for (idx, typex, expr), child_scope in zip(node.branches, scope.children[1:]): + self.visit(expr, child_scope) + expr_type = expr.static_type + + node.static_type = node.static_type.type_union(expr_type) if node.static_type else expr_type + + @visitor.when(AssignNode) + def visit(self, node, scope, expected_type=None): + var = scope.find_variable(node.id.lex) if scope.is_defined(node.id.lex) else None + + self.visit(node.expression, scope.children[0], var.type if var and var.infered else expected_type) + expr_type = node.expression.static_type + + var.set_assigns(expr_type) + + node.static_type = expr_type + + @visitor.when(NotNode) + def visit(self, node, scope, expected_type=None): + # posible inferencia + self.visit(node.expression, scope.children[0], self.bool_type) + + node.static_type = self.bool_type + + @visitor.when(LessEqualNode) + def visit(self, node, scope, expected_type=None): + # posible inferencia + self.visit(node.left, scope.children[0], self.int_type) + + # posible inferencia + self.visit(node.right, scope.children[1], self.int_type) + + node.static_type = self.bool_type + + @visitor.when(LessNode) + def visit(self, node, scope, expected_type=None): + # posible inferencia + self.visit(node.left, scope.children[0], self.int_type) + + # posible inferencia + self.visit(node.right, scope.children[1], self.int_type) + + node.static_type = self.bool_type + + @visitor.when(EqualNode) + def visit(self, node, scope, expected_type=None): + # posible inferencia + self.visit(node.left, scope.children[0], node.right.static_type) + + # posible inferencia + self.visit(node.right, scope.children[1], node.left.static_type) + + node.static_type = self.bool_type + + @visitor.when(ArithmeticNode) + def visit(self, node, scope, expected_type=None): + # posible inferencia + self.visit(node.left, scope.children[0], self.int_type) + + # posible inferencia + self.visit(node.right, scope.children[1], self.int_type) + + node.static_type = self.int_type + + @visitor.when(IsVoidNode) + def visit(self, node, scope, expected_type=None): + self.visit(node.expression, scope.children[0]) + + node.static_type = self.bool_type + + @visitor.when(ComplementNode) + def visit(self, node, scope, expected_type=None): + # posible inferencia + self.visit(node.expression, scope.children[0], self.int_type) + + node.static_type = self.int_type + + @visitor.when(FunctionCallNode) + def visit(self, node, scope, expected_type=None): + node_type = None + if node.type: + try: + node_type = self.context.get_type(node.type.lex) + except SemanticError: + node_type = ErrorType() + else: + if isinstance(node_type, SelfType) or isinstance(node_type, AutoType): + node_type = ErrorType() + + self.visit(node.obj, scope.children[0], node_type) + obj_type = node.obj.static_type + + try: + obj_type = node_type if node_type else obj_type + + obj_method = obj_type.get_method(node.id.lex) + + # setear el expected_type al retorno + node_type = obj_type if isinstance(obj_method.return_type, SelfType) else obj_method.return_type + except SemanticError: + node_type = ErrorType() + obj_method = None + + if obj_method and len(node.args) == len(obj_method.param_types): + for arg, var, child_scope in zip(node.args, obj_method.param_infos, scope.children[1:]): + self.visit(arg, child_scope, var.type if var.infered else None) + # inferir var.type por arg_type + else: + for arg, child_scope in zip(node.args, scope.children[1:]): + self.visit(arg, child_scope) + + node.static_type = node_type + + @visitor.when(MemberCallNode) + def visit(self, node, scope, expected_type=None): + obj_type = self.current_type + + try: + obj_method = obj_type.get_method(node.id.lex) + + # setear el expected_type al retorno + node_type = obj_type if isinstance(obj_method.return_type, SelfType) else obj_method.return_type + except SemanticError: + node_type = ErrorType() + obj_method = None + + if obj_method and len(node.args) == len(obj_method.param_types): + for arg, var, child_scope in zip(node.args, obj_method.param_infos, scope.children): + self.visit(arg, child_scope, var.type if var.infered else None) + # inferir var.type por arg_type + else: + for arg, child_scope in zip(node.args, scope.children): + self.visit(arg, child_scope) + + + node.static_type = node_type + + @visitor.when(NewNode) + def visit(self, node, scope, expected_type=None): + try: + node_type = self.context.get_type(node.type.lex) + except SemanticError: + node_type = ErrorType() + + node.static_type = node_type + + @visitor.when(IntegerNode) + def visit(self, node, scope, expected_type=None): + node.static_type = self.int_type + + @visitor.when(StringNode) + def visit(self, node, scope, expected_type=None): + node.static_type = self.string_type + + @visitor.when(IdNode) + def visit(self, node, scope, expected_type=None): + if scope.is_defined(node.token.lex): + var = scope.find_variable(node.token.lex) + + if expected_type: + var.set_calls(expected_type) + + node_type = var.type if var.infered else AutoType() + else: + node_type = ErrorType() + + node.static_type = node_type + + @visitor.when(BoolNode) + def visit(self, node, scope, expected_type=None): + node.static_type = self.bool_type \ No newline at end of file diff --git a/src/main.py b/src/main.py new file mode 100644 index 00000000..a54affca --- /dev/null +++ b/src/main.py @@ -0,0 +1,115 @@ +#!/usr/bin/python3 + +from engine import * +import sys + + +def compile_code(inFile, outFile, output_cil=False): + input_file = open(inFile, "r") + output_file = open(outFile, 'w') + + text_code = input_file.read() + + ast = parse(text_code) + context = collect(ast) + context = builder(ast, context) + context = checker(ast, context) + + string_formatted = codegen(ast, context, output_cil) + output_file.write(string_formatted) + + input_file.close() + output_file.close() + + exit(0) + + +def parse(text_code): + lexer = CoolLexer() + tokens, errors = lexer.tokenize(text_code) + + if len(errors): + for e in errors: + print(e) + exit(1) + + if not tokens: + print(SyntacticError(0, 0, 'ERROR at or near "%s"' % 'EOF')) + exit(1) + + lexer = CoolLexer() + parser = CoolParser(lexer) + ast, errors = parser.parse(text_code) + + if errors: + for error in errors: + print(error) + exit(1) + # print(ast) + + # fmatter = Format() + # tree = fmatter.visit(ast, 0) + + # print(tree) + return ast + + +def collect(ast): + collect_errors = [] + collect = Collector(collect_errors) + collect.visit(ast) + + if len(collect_errors): + for e in collect_errors[::-1]: + print(e) + exit(1) + return collect.context + + +def builder(ast, context): + builder_errors = [] + builder = Builder(context, builder_errors) + + builder.visit(ast) + + if len(builder_errors): + for e in builder_errors: + print(e) + exit(1) + return builder.context + + +def checker(ast, context): + checker_errors = [] + checker = Checker(context, checker_errors) + scope = checker.visit(ast, Scope()) + + if len(checker_errors): + for e in checker_errors: + print(e) + exit(1) + return checker.context + + +def codegen(ast, context, output_cil=False): + cil = COOL_TO_CIL(context) + cil_ast = cil.visit(ast) + + if output_cil: + formatted_ast = CIL_FORMATTER().visit(cil_ast) + with open('out.cil', 'w') as f: + f.write(formatted_ast) + + emsamb = CIL_TO_MIPS() + emsamb.visit(cil_ast) + + f_ast = emsamb.mips.compile() + + return str(f_ast) + + +if __name__ == "__main__": + args = sys.argv + if not len(args) in (3, 4): + exit(1) + compile_code(*args[1:]) diff --git a/src/makefile b/src/makefile index 30df993f..354c0a07 100644 --- a/src/makefile +++ b/src/makefile @@ -10,3 +10,6 @@ clean: test: pytest ../tests -v --tb=short -m=${TAG} +quick_test: + bash coolc.sh test.cl + diff --git a/src/out.cil b/src/out.cil new file mode 100644 index 00000000..55f80626 --- /dev/null +++ b/src/out.cil @@ -0,0 +1,273 @@ +.TYPES +type Object { + + + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object +} +type String { + attribute value + + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object + method length: function_length_at_String + method concat: function_concat_at_String + method substr: function_substr_at_String +} +type IO { + + + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object + method out_string: function_out_string_at_IO + method out_int: function_out_int_at_IO + method in_string: function_in_string_at_IO + method in_int: function_in_int_at_IO +} +type Int { + attribute value + + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object +} +type Bool { + attribute value + + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object +} +type Main { + + + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object + method out_string: function_out_string_at_IO + method out_int: function_out_int_at_IO + method in_string: function_in_string_at_IO + method in_int: function_in_int_at_IO + method main: function_main_at_Main +} + +.DATA +data_0 = "Abort called from class " +data_1 = " +" +data_2 = "Invalid substring start" +data_3 = "Invalid substring length" +data_4 = "" + +.CODE +function function_abort_at_Object { + PARAM self + + LOCAL local_abort_at_Object_internal_0 + LOCAL local_abort_at_Object_internal_1 + LOCAL local_abort_at_Object_internal_2 + LOCAL local_abort_at_Object_internal_3 + LOCAL local_abort_at_Object_internal_4 + + local_abort_at_Object_internal_2 = LOAD data_0 + local_abort_at_Object_internal_3 = LOAD data_1 + local_abort_at_Object_internal_4 = TYPEOF self + local_abort_at_Object_internal_0 = TYPENAME local_abort_at_Object_internal_4 + local_abort_at_Object_internal_1 = CONCAT local_abort_at_Object_internal_2 local_abort_at_Object_internal_0 + local_abort_at_Object_internal_1 = CONCAT local_abort_at_Object_internal_1 local_abort_at_Object_internal_3 + PRINTSTR local_abort_at_Object_internal_1 + ABORT +} +function function_copy_at_Object { + PARAM self + + LOCAL local_copy_at_Object_internal_0 + + local_copy_at_Object_internal_0 = COPY self + RETURN local_copy_at_Object_internal_0 +} +function function_type_name_at_Object { + PARAM self + + LOCAL local_type_name_at_Object_internal_0 + LOCAL local_type_name_at_Object_internal_1 + + local_type_name_at_Object_internal_1 = TYPEOF self + local_type_name_at_Object_internal_0 = TYPENAME local_type_name_at_Object_internal_1 + RETURN local_type_name_at_Object_internal_0 +} +function function_length_at_String { + PARAM self + + LOCAL local_length_at_String_internal_0 + LOCAL local_length_at_String_internal_1 + + local_length_at_String_internal_1 = GETATTR self value + local_length_at_String_internal_0 = LENGTH local_length_at_String_internal_1 + RETURN local_length_at_String_internal_0 +} +function function_concat_at_String { + PARAM self + PARAM string + + LOCAL local_concat_at_String_internal_0 + LOCAL local_concat_at_String_internal_1 + + local_concat_at_String_internal_1 = GETATTR self value + local_concat_at_String_internal_0 = CONCAT local_concat_at_String_internal_1 string + RETURN local_concat_at_String_internal_0 +} +function function_substr_at_String { + PARAM self + PARAM start + PARAM length + + LOCAL local_substr_at_String_internal_0 + LOCAL local_substr_at_String_internal_1 + LOCAL local_substr_at_String_internal_2 + LOCAL local_substr_at_String_internal_3 + LOCAL local_substr_at_String_internal_4 + LOCAL local_substr_at_String_internal_5 + LOCAL local_substr_at_String_internal_6 + LOCAL local_substr_at_String_internal_7 + LOCAL local_substr_at_String_internal_8 + + local_substr_at_String_internal_0 = GETATTR self value + local_substr_at_String_internal_6 = 0 + local_substr_at_String_internal_7 = LENGTH local_substr_at_String_internal_0 + local_substr_at_String_internal_8 = LOAD data_1 + local_substr_at_String_internal_2 = local_substr_at_String_internal_6 <= start + IF local_substr_at_String_internal_2 GOTO error1 + local_substr_at_String_internal_4 = LOAD data_2 + local_substr_at_String_internal_4 = CONCAT local_substr_at_String_internal_4 local_substr_at_String_internal_8 + PRINTSTR local_substr_at_String_internal_4 + ERROR 0 + LABEL error1 + local_substr_at_String_internal_3 = local_substr_at_String_internal_6 <= length + IF local_substr_at_String_internal_3 GOTO error2 + local_substr_at_String_internal_5 = LOAD data_3 + local_substr_at_String_internal_5 = CONCAT local_substr_at_String_internal_5 local_substr_at_String_internal_8 + PRINTSTR local_substr_at_String_internal_5 + ERROR 0 + LABEL error2 + local_substr_at_String_internal_1 = SUBSTRING local_substr_at_String_internal_0 start length + RETURN local_substr_at_String_internal_1 +} +function function_out_string_at_IO { + PARAM self + PARAM str_val + + + + PRINTSTR str_val + RETURN self +} +function function_in_string_at_IO { + + + LOCAL local_in_string_at_IO_internal_0 + + local_in_string_at_IO_internal_0 = READSTR + RETURN local_in_string_at_IO_internal_0 +} +function function_out_int_at_IO { + PARAM self + PARAM int_val + + + + PRINTINT int_val + RETURN self +} +function function_in_int_at_IO { + + + LOCAL local_in_int_at_IO_internal_0 + + local_in_int_at_IO_internal_0 = READINT + RETURN local_in_int_at_IO_internal_0 +} +function ctor_IO { + PARAM self + + + + RETURN self +} +function ctor_Int { + PARAM self + + LOCAL local__internal_0 + + VOID + SETATTR value OF self_Int = local__internal_0 + RETURN self +} +function ctor_String { + PARAM self + + + + SETATTR value OF self_String = data_4 + RETURN self +} +function ctor_Bool { + PARAM self + + LOCAL local__internal_0 + + VOID + SETATTR value OF self_Bool = local__internal_0 + RETURN self +} +function ctor_Object { + PARAM self + + + + RETURN self +} +function ctor_Main { + PARAM self + + + + RETURN self +} +function entry { + + + LOCAL local__internal_0 + LOCAL local__internal_1 + + local__internal_0 = ALLOCATE Main + ARG local__internal_0 + local__internal_0 = CALL ctor_Main + CLEAR 1 ARGS + ARG local__internal_0 + local__internal_1 = CALL function_main_at_Main + CLEAR 1 ARGS +} +function function_main_at_Main { + PARAM self + + LOCAL local_main_at_Main_internal_0 + LOCAL local_main_at_Main_internal_1 + LOCAL local_main_at_Main_internal_2 + + local_main_at_Main_internal_2 = ALLOCATE Object + ARG local_main_at_Main_internal_2 + local_main_at_Main_internal_2 = CALL ctor_Object + CLEAR 1 ARGS + ARG local_main_at_Main_internal_2 + local_main_at_Main_internal_1 = VCALL Object type_name + CLEAR 1 ARGS + ARG local_main_at_Main_internal_1 + ARG self + local_main_at_Main_internal_0 = VCALL Main out_string + CLEAR 2 ARGS + RETURN local_main_at_Main_internal_0 +} \ No newline at end of file diff --git a/src/program1.cl b/src/program1.cl new file mode 100644 index 00000000..33cbcd02 --- /dev/null +++ b/src/program1.cl @@ -0,0 +1 @@ +(* A Cool program can't be empty *) diff --git a/src/program1_error.txt b/src/program1_error.txt new file mode 100644 index 00000000..de00ac46 --- /dev/null +++ b/src/program1_error.txt @@ -0,0 +1 @@ +(0, 0) - SyntacticError: ERROR at or near EOF \ No newline at end of file diff --git a/src/test.cl b/src/test.cl new file mode 100644 index 00000000..b9e90b32 --- /dev/null +++ b/src/test.cl @@ -0,0 +1,5 @@ +class Main inherits IO { + main () : IO { + out_string((new Object).type_name()) + } ; +} ; diff --git a/src/test.mips b/src/test.mips new file mode 100644 index 00000000..3bd01244 --- /dev/null +++ b/src/test.mips @@ -0,0 +1,1791 @@ +.data +classname_Object: +.asciiz "Object" +classname_String: +.asciiz "String" +classname_IO: +.asciiz "IO" +classname_Int: +.asciiz "Int" +classname_Bool: +.asciiz "Bool" +classname_Main: +.asciiz "Main" +data_0: +.asciiz "Abort called from class " +data_1: +.asciiz " +" +data_2: +.asciiz "Invalid substring start" +data_3: +.asciiz "Invalid substring length" +data_4: +.asciiz "" +.text +main: +# Allocate Vtable +li $a0, 120 +li $v0, 9 +syscall +move $s7, $v0 +# Build VTable +# Object_abort +la $s0, function_abort_at_Object +sw $s0, 0($s7) +# Object_type_name +la $s0, function_type_name_at_Object +sw $s0, 4($s7) +# Object_copy +la $s0, function_copy_at_Object +sw $s0, 8($s7) +# String_abort +la $s0, function_abort_at_Object +sw $s0, 12($s7) +# String_type_name +la $s0, function_type_name_at_Object +sw $s0, 16($s7) +# String_copy +la $s0, function_copy_at_Object +sw $s0, 20($s7) +# String_length +la $s0, function_length_at_String +sw $s0, 24($s7) +# String_concat +la $s0, function_concat_at_String +sw $s0, 28($s7) +# String_substr +la $s0, function_substr_at_String +sw $s0, 32($s7) +# IO_abort +la $s0, function_abort_at_Object +sw $s0, 36($s7) +# IO_type_name +la $s0, function_type_name_at_Object +sw $s0, 40($s7) +# IO_copy +la $s0, function_copy_at_Object +sw $s0, 44($s7) +# IO_out_string +la $s0, function_out_string_at_IO +sw $s0, 48($s7) +# IO_out_int +la $s0, function_out_int_at_IO +sw $s0, 52($s7) +# IO_in_string +la $s0, function_in_string_at_IO +sw $s0, 56($s7) +# IO_in_int +la $s0, function_in_int_at_IO +sw $s0, 60($s7) +# Int_abort +la $s0, function_abort_at_Object +sw $s0, 64($s7) +# Int_type_name +la $s0, function_type_name_at_Object +sw $s0, 68($s7) +# Int_copy +la $s0, function_copy_at_Object +sw $s0, 72($s7) +# Bool_abort +la $s0, function_abort_at_Object +sw $s0, 76($s7) +# Bool_type_name +la $s0, function_type_name_at_Object +sw $s0, 80($s7) +# Bool_copy +la $s0, function_copy_at_Object +sw $s0, 84($s7) +# Main_abort +la $s0, function_abort_at_Object +sw $s0, 88($s7) +# Main_type_name +la $s0, function_type_name_at_Object +sw $s0, 92($s7) +# Main_copy +la $s0, function_copy_at_Object +sw $s0, 96($s7) +# Main_out_string +la $s0, function_out_string_at_IO +sw $s0, 100($s7) +# Main_out_int +la $s0, function_out_int_at_IO +sw $s0, 104($s7) +# Main_in_string +la $s0, function_in_string_at_IO +sw $s0, 108($s7) +# Main_in_int +la $s0, function_in_int_at_IO +sw $s0, 112($s7) +# Main_main +la $s0, function_main_at_Main +sw $s0, 116($s7) +jal entry + +li $v0, 10 +syscall +function_abort_at_Object: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -20 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# Load from data_0 to $s0 +la $s0, data_0 +# from src: $s0 to dst: local_abort_at_Object_internal_2 +sw $s0, -12($fp) + +# Load from data_1 to $s0 +la $s0, data_1 +# from src: $s0 to dst: local_abort_at_Object_internal_3 +sw $s0, -16($fp) + +# TypeOfNode of self +# Load from self to $s0 +lw $s0, 4($fp) +lw $s1, 3($s0) +# from src: $s1 to dst: local_abort_at_Object_internal_4 +sw $s1, -20($fp) + +# TypeNameNode +# Load from local_abort_at_Object_internal_4 to $t0 +lw $t0, -20($fp) +lw $t1, 4($t0) +# from src: $t1 to dst: local_abort_at_Object_internal_0 +sw $t1, -4($fp) + +# Load from local_abort_at_Object_internal_2 to $s0 +lw $s0, -12($fp) +# Load from local_abort_at_Object_internal_0 to $s1 +lw $s1, -4($fp) +move $t0, $s0 +li $t1, 0 +mips_label_1: +lb $t3, 0($t0) +beqz $t3, mips_label_2 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_1 +mips_label_2: +move $s4, $t1 +move $t0, $s1 +li $t1, 0 +mips_label_3: +lb $t3, 0($t0) +beqz $t3, mips_label_4 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_3 +mips_label_4: +move $s5, $t1 +add $a0, $s4, $s5 +li $v0, 9 +syscall +move $s3, $v0 +move $t0, $s0 +move $t1, $s3 +mips_label_5: +lb $t2, 0($t0) +sb $t2, 0($t1) +beqz $t2, mips_label_6 +addi $t0, $t0, 1 +addi $t1, $t1, 1 +j mips_label_5 +mips_label_6: +move $v0, $t1 +move $t0, $s1 +move $t1, $v0 +mips_label_7: +lb $t2, 0($t0) +sb $t2, 0($t1) +beqz $t2, mips_label_8 +addi $t0, $t0, 1 +addi $t1, $t1, 1 +j mips_label_7 +mips_label_8: +move $v0, $t1 +# from src: $s3 to dst: local_abort_at_Object_internal_1 +sw $s3, -8($fp) + +# Load from local_abort_at_Object_internal_1 to $s0 +lw $s0, -8($fp) +# Load from local_abort_at_Object_internal_3 to $s1 +lw $s1, -16($fp) +move $t0, $s0 +li $t1, 0 +mips_label_9: +lb $t3, 0($t0) +beqz $t3, mips_label_10 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_9 +mips_label_10: +move $s4, $t1 +move $t0, $s1 +li $t1, 0 +mips_label_11: +lb $t3, 0($t0) +beqz $t3, mips_label_12 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_11 +mips_label_12: +move $s5, $t1 +add $a0, $s4, $s5 +li $v0, 9 +syscall +move $s3, $v0 +move $t0, $s0 +move $t1, $s3 +mips_label_13: +lb $t2, 0($t0) +sb $t2, 0($t1) +beqz $t2, mips_label_14 +addi $t0, $t0, 1 +addi $t1, $t1, 1 +j mips_label_13 +mips_label_14: +move $v0, $t1 +move $t0, $s1 +move $t1, $v0 +mips_label_15: +lb $t2, 0($t0) +sb $t2, 0($t1) +beqz $t2, mips_label_16 +addi $t0, $t0, 1 +addi $t1, $t1, 1 +j mips_label_15 +mips_label_16: +move $v0, $t1 +# from src: $s3 to dst: local_abort_at_Object_internal_1 +sw $s3, -8($fp) + +# Print str local_abort_at_Object_internal_1 +# Load from local_abort_at_Object_internal_1 to $a0 +lw $a0, -8($fp) +li $v0, 4 +syscall +li $v0, 10 +syscall + + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 20 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +function_copy_at_Object: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -4 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +la $s1, -4($fp) +li $s3, 0 +move $t0, $s0 +move $t1, $s1 +move $t3, $s3 +mips_label_17: +lb $t2, 0($t0) +sb $t2, 0($t1) +addi $t0, $t0, 2 +addi $t1, $t1, 2 +addi $t3, $t3, -1 +beqz $t3, mips_label_18 +j mips_label_17 +mips_label_18: +# ReturnNode +# Load from local_copy_at_Object_internal_0 to $v0 +lw $v0, -4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 4 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +function_type_name_at_Object: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -8 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# TypeOfNode of self +# Load from self to $s0 +lw $s0, 4($fp) +lw $s1, 3($s0) +# from src: $s1 to dst: local_type_name_at_Object_internal_1 +sw $s1, -8($fp) + +# TypeNameNode +# Load from local_type_name_at_Object_internal_1 to $t0 +lw $t0, -8($fp) +lw $t1, 4($t0) +# from src: $t1 to dst: local_type_name_at_Object_internal_0 +sw $t1, -4($fp) + +# ReturnNode +# Load from local_type_name_at_Object_internal_0 to $v0 +lw $v0, -4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 8 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +function_length_at_String: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -8 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# GetAttribNode local_length_at_String_internal_1 = self.value Type:String +# Load from self to $t0 +lw $t0, 4($fp) +lw $t1, 16($t0) +# from src: $t1 to dst: local_length_at_String_internal_1 +sw $t1, -8($fp) + +# LengthNode +# Load from local_length_at_String_internal_1 to $s1 +lw $s1, -8($fp) +move $t0, $s1 +li $t1, 0 +mips_label_19: +lb $t3, 0($t0) +beqz $t3, mips_label_20 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_19 +mips_label_20: +move $s0, $t1 +# from src: $s0 to dst: local_length_at_String_internal_0 +sw $s0, -4($fp) + +# ReturnNode +# Load from local_length_at_String_internal_0 to $v0 +lw $v0, -4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 8 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +function_concat_at_String: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -8 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# GetAttribNode local_concat_at_String_internal_1 = self.value Type:String +# Load from self to $t0 +lw $t0, 4($fp) +lw $t1, 16($t0) +# from src: $t1 to dst: local_concat_at_String_internal_1 +sw $t1, -8($fp) + +# Load from local_concat_at_String_internal_1 to $s0 +lw $s0, -8($fp) +# Load from string to $s1 +lw $s1, 8($fp) +move $t0, $s0 +li $t1, 0 +mips_label_21: +lb $t3, 0($t0) +beqz $t3, mips_label_22 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_21 +mips_label_22: +move $s4, $t1 +move $t0, $s1 +li $t1, 0 +mips_label_23: +lb $t3, 0($t0) +beqz $t3, mips_label_24 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_23 +mips_label_24: +move $s5, $t1 +add $a0, $s4, $s5 +li $v0, 9 +syscall +move $s3, $v0 +move $t0, $s0 +move $t1, $s3 +mips_label_25: +lb $t2, 0($t0) +sb $t2, 0($t1) +beqz $t2, mips_label_26 +addi $t0, $t0, 1 +addi $t1, $t1, 1 +j mips_label_25 +mips_label_26: +move $v0, $t1 +move $t0, $s1 +move $t1, $v0 +mips_label_27: +lb $t2, 0($t0) +sb $t2, 0($t1) +beqz $t2, mips_label_28 +addi $t0, $t0, 1 +addi $t1, $t1, 1 +j mips_label_27 +mips_label_28: +move $v0, $t1 +# from src: $s3 to dst: local_concat_at_String_internal_0 +sw $s3, -4($fp) + +# ReturnNode +# Load from local_concat_at_String_internal_0 to $v0 +lw $v0, -4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 8 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +function_substr_at_String: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -36 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# GetAttribNode local_substr_at_String_internal_0 = self.value Type:String +# Load from self to $t0 +lw $t0, 4($fp) +lw $t1, 16($t0) +# from src: $t1 to dst: local_substr_at_String_internal_0 +sw $t1, -4($fp) + +li $s0, 0 +# from src: $s0 to dst: local_substr_at_String_internal_6 +sw $s0, -28($fp) + +# LengthNode +# Load from local_substr_at_String_internal_0 to $s1 +lw $s1, -4($fp) +move $t0, $s1 +li $t1, 0 +mips_label_29: +lb $t3, 0($t0) +beqz $t3, mips_label_30 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_29 +mips_label_30: +move $s0, $t1 +# from src: $s0 to dst: local_substr_at_String_internal_7 +sw $s0, -32($fp) + +# Load from data_1 to $s0 +la $s0, data_1 +# from src: $s0 to dst: local_substr_at_String_internal_8 +sw $s0, -36($fp) + +# Load from local_substr_at_String_internal_6 to $t0 +lw $t0, -28($fp) +# Load from start to $t1 +lw $t1, 8($fp) +slt $t2, $t1, $t0 +li $t3, 1 +sub $t0, $t3, $t2 +# from src: $t0 to dst: local_substr_at_String_internal_2 +sw $t0, -12($fp) + +# IfGotoNode +# Load from local_substr_at_String_internal_2 to $t0 +lw $t0, -12($fp) +li $t1, 0 +bne $t0, $t1, error1 +# Load from data_2 to $s0 +la $s0, data_2 +# from src: $s0 to dst: local_substr_at_String_internal_4 +sw $s0, -20($fp) + +# Load from local_substr_at_String_internal_4 to $s0 +lw $s0, -20($fp) +# Load from local_substr_at_String_internal_8 to $s1 +lw $s1, -36($fp) +move $t0, $s0 +li $t1, 0 +mips_label_31: +lb $t3, 0($t0) +beqz $t3, mips_label_32 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_31 +mips_label_32: +move $s4, $t1 +move $t0, $s1 +li $t1, 0 +mips_label_33: +lb $t3, 0($t0) +beqz $t3, mips_label_34 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_33 +mips_label_34: +move $s5, $t1 +add $a0, $s4, $s5 +li $v0, 9 +syscall +move $s3, $v0 +move $t0, $s0 +move $t1, $s3 +mips_label_35: +lb $t2, 0($t0) +sb $t2, 0($t1) +beqz $t2, mips_label_36 +addi $t0, $t0, 1 +addi $t1, $t1, 1 +j mips_label_35 +mips_label_36: +move $v0, $t1 +move $t0, $s1 +move $t1, $v0 +mips_label_37: +lb $t2, 0($t0) +sb $t2, 0($t1) +beqz $t2, mips_label_38 +addi $t0, $t0, 1 +addi $t1, $t1, 1 +j mips_label_37 +mips_label_38: +move $v0, $t1 +# from src: $s3 to dst: local_substr_at_String_internal_4 +sw $s3, -20($fp) + +# Print str local_substr_at_String_internal_4 +# Load from local_substr_at_String_internal_4 to $a0 +lw $a0, -20($fp) +li $v0, 4 +syscall +# ErrorNode +li $a0, 1 +li $v0, 17 +syscall +error1: +# Load from local_substr_at_String_internal_6 to $t0 +lw $t0, -28($fp) +# Load from length to $t1 +lw $t1, 12($fp) +slt $t2, $t1, $t0 +li $t3, 1 +sub $t0, $t3, $t2 +# from src: $t0 to dst: local_substr_at_String_internal_3 +sw $t0, -16($fp) + +# IfGotoNode +# Load from local_substr_at_String_internal_3 to $t0 +lw $t0, -16($fp) +li $t1, 0 +bne $t0, $t1, error2 +# Load from data_3 to $s0 +la $s0, data_3 +# from src: $s0 to dst: local_substr_at_String_internal_5 +sw $s0, -24($fp) + +# Load from local_substr_at_String_internal_5 to $s0 +lw $s0, -24($fp) +# Load from local_substr_at_String_internal_8 to $s1 +lw $s1, -36($fp) +move $t0, $s0 +li $t1, 0 +mips_label_39: +lb $t3, 0($t0) +beqz $t3, mips_label_40 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_39 +mips_label_40: +move $s4, $t1 +move $t0, $s1 +li $t1, 0 +mips_label_41: +lb $t3, 0($t0) +beqz $t3, mips_label_42 +addi $t1, $t1, 1 +addi $t0, $t0, 1 +j mips_label_41 +mips_label_42: +move $s5, $t1 +add $a0, $s4, $s5 +li $v0, 9 +syscall +move $s3, $v0 +move $t0, $s0 +move $t1, $s3 +mips_label_43: +lb $t2, 0($t0) +sb $t2, 0($t1) +beqz $t2, mips_label_44 +addi $t0, $t0, 1 +addi $t1, $t1, 1 +j mips_label_43 +mips_label_44: +move $v0, $t1 +move $t0, $s1 +move $t1, $v0 +mips_label_45: +lb $t2, 0($t0) +sb $t2, 0($t1) +beqz $t2, mips_label_46 +addi $t0, $t0, 1 +addi $t1, $t1, 1 +j mips_label_45 +mips_label_46: +move $v0, $t1 +# from src: $s3 to dst: local_substr_at_String_internal_5 +sw $s3, -24($fp) + +# Print str local_substr_at_String_internal_5 +# Load from local_substr_at_String_internal_5 to $a0 +lw $a0, -24($fp) +li $v0, 4 +syscall +# ErrorNode +li $a0, 1 +li $v0, 17 +syscall +error2: +# Load from local_substr_at_String_internal_0 to $s0 +lw $s0, -4($fp) +# Load from length to $s1 +lw $s1, 12($fp) +# Load from start to $s3 +lw $s3, 8($fp) +add $s0, $s0, $s3 +move $a0, $s1 +li $v0, 9 +syscall +move $t0, $s0 +move $t1, $v0 +move $t3, $s1 +mips_label_47: +lb $t2, 0($t0) +sb $t2, 0($t1) +addi $t0, $t0, 1 +addi $t1, $t1, 1 +addi $t3, $t3, -1 +beqz $t3, mips_label_48 +j mips_label_47 +mips_label_48: +move $t2, $zero +sb $t2, 0($t1) +# from src: $v0 to dst: local_substr_at_String_internal_1 +sw $v0, -8($fp) + +# ReturnNode +# Load from local_substr_at_String_internal_1 to $v0 +lw $v0, -8($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 36 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +function_out_string_at_IO: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, 0 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# Print str str_val +# Load from str_val to $a0 +lw $a0, 8($fp) +li $v0, 4 +syscall +# ReturnNode +# Load from self to $v0 +lw $v0, 4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 0 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +function_in_string_at_IO: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -4 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +li $a0, 1024 +li $v0, 9 +syscall +move $a0, $v0 +# from src: $v0 to dst: local_in_string_at_IO_internal_0 +sw $v0, -4($fp) + +li $a1, 1024 +li $v0, 8 +syscall +# ReturnNode +# Load from local_in_string_at_IO_internal_0 to $v0 +lw $v0, -4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 4 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +function_out_int_at_IO: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, 0 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# Load from int_val to $a0 +lw $a0, 8($fp) +li $v0, 1 +syscall +# ReturnNode +# Load from self to $v0 +lw $v0, 4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 0 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +function_in_int_at_IO: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -4 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +li $v0, 5 +syscall +# from src: $v0 to dst: local_in_int_at_IO_internal_0 +sw $v0, -4($fp) + +# ReturnNode +# Load from local_in_int_at_IO_internal_0 to $v0 +lw $v0, -4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 4 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +ctor_IO: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, 0 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# ReturnNode +# Load from self to $v0 +lw $v0, 4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 0 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +ctor_Int: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -4 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# from src: $zero to dst: local__internal_0 +sw $zero, -4($fp) + +# SetAttribNode self.value Type:Int = local__internal_0 +# Load from self to $s0 +lw $s0, 4($fp) +# SET local var local__internal_0 +# Load from local__internal_0 to $s1 +lw $s1, -4($fp) +sw $s1, 16($s0) +# ReturnNode +# Load from self to $v0 +lw $v0, 4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 4 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +ctor_String: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, 0 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# SetAttribNode self.value Type:String = data_4 +# Load from self to $s0 +lw $s0, 4($fp) +# SET data data_4 +la $s1, data_4 +sw $s1, 16($s0) +# ReturnNode +# Load from self to $v0 +lw $v0, 4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 0 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +ctor_Bool: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -4 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# from src: $zero to dst: local__internal_0 +sw $zero, -4($fp) + +# SetAttribNode self.value Type:Bool = local__internal_0 +# Load from self to $s0 +lw $s0, 4($fp) +# SET local var local__internal_0 +# Load from local__internal_0 to $s1 +lw $s1, -4($fp) +sw $s1, 16($s0) +# ReturnNode +# Load from self to $v0 +lw $v0, 4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 4 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +ctor_Object: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, 0 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# ReturnNode +# Load from self to $v0 +lw $v0, 4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 0 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +ctor_Main: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, 0 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# ReturnNode +# Load from self to $v0 +lw $v0, 4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 0 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +entry: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -8 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# Allocate space for Main +li $a0, 16 +li $v0, 9 +syscall +move $s1, $v0 +# from src: $s1 to dst: local__internal_0 +sw $s1, -4($fp) + +li $s0, 5 +sw $s0, 0($s1) +li $s0, 16 +sw $s0, 4($s1) +la $s0, classname_Main +sw $s0, 8($s1) +li $s0, 88 +sw $s0, 12($s1) +# ArgNode local__internal_0 to s0 +# Load from local__internal_0 to $s0 +lw $s0, -4($fp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +# StaticCallNode +jal ctor_Main +# from src: $v0 to dst: local__internal_0 +sw $v0, -4($fp) + +addi $sp, $sp, 4 +# ArgNode local__internal_0 to s0 +# Load from local__internal_0 to $s0 +lw $s0, -4($fp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +# StaticCallNode +jal function_main_at_Main +# from src: $v0 to dst: local__internal_1 +sw $v0, -8($fp) + +addi $sp, $sp, 4 + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 8 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra + +function_main_at_Main: +# Set stack frame +addi $sp, $sp, -4 +sw $fp, 0($sp) +move $fp, $sp + +# Allocate memory for Local variables +addi $sp, $sp, -12 + + +# Saving Registers +addi $sp, $sp, -4 +sw $ra, 0($sp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +addi $sp, $sp, -4 +sw $s1, 0($sp) +addi $sp, $sp, -4 +sw $s2, 0($sp) +addi $sp, $sp, -4 +sw $s3, 0($sp) +addi $sp, $sp, -4 +sw $s4, 0($sp) +addi $sp, $sp, -4 +sw $s5, 0($sp) +addi $sp, $sp, -4 +sw $s6, 0($sp) + +# Generating body code +# Allocate space for Object +li $a0, 16 +li $v0, 9 +syscall +move $s1, $v0 +# from src: $s1 to dst: local_main_at_Main_internal_2 +sw $s1, -12($fp) + +li $s0, 0 +sw $s0, 0($s1) +li $s0, 16 +sw $s0, 4($s1) +la $s0, classname_Object +sw $s0, 8($s1) +li $s0, 0 +sw $s0, 12($s1) +# ArgNode local_main_at_Main_internal_2 to s0 +# Load from local_main_at_Main_internal_2 to $s0 +lw $s0, -12($fp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +# StaticCallNode +jal ctor_Object +# from src: $v0 to dst: local_main_at_Main_internal_2 +sw $v0, -12($fp) + +addi $sp, $sp, 4 +# ArgNode local_main_at_Main_internal_2 to s0 +# Load from local_main_at_Main_internal_2 to $s0 +lw $s0, -12($fp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +# DynamicCallNode Object type_name +# Load from local_main_at_Main_internal_2 to $s0 +lw $s0, -12($fp) +lw $s1, 12($s0) +addi $s2, $s1, 4 +addu $s3, $s2, $s7 +lw $s4, 0($s3) +jalr $s4 +# from src: $v0 to dst: local_main_at_Main_internal_1 +sw $v0, -8($fp) + +addi $sp, $sp, 4 +# ArgNode local_main_at_Main_internal_1 to s0 +# Load from local_main_at_Main_internal_1 to $s0 +lw $s0, -8($fp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +# ArgNode self to s0 +# Load from self to $s0 +lw $s0, 4($fp) +addi $sp, $sp, -4 +sw $s0, 0($sp) +# DynamicCallNode Main out_string +# Load from self to $s0 +lw $s0, 4($fp) +lw $s1, 12($s0) +addi $s2, $s1, 12 +addu $s3, $s2, $s7 +lw $s4, 0($s3) +jalr $s4 +# from src: $v0 to dst: local_main_at_Main_internal_0 +sw $v0, -4($fp) + +addi $sp, $sp, 8 +# ReturnNode +# Load from local_main_at_Main_internal_0 to $v0 +lw $v0, -4($fp) + +# Restore registers +lw $s6, 0($sp) +addi $sp, $sp, 4 +lw $s5, 0($sp) +addi $sp, $sp, 4 +lw $s4, 0($sp) +addi $sp, $sp, 4 +lw $s3, 0($sp) +addi $sp, $sp, 4 +lw $s2, 0($sp) +addi $sp, $sp, 4 +lw $s1, 0($sp) +addi $sp, $sp, 4 +lw $s0, 0($sp) +addi $sp, $sp, 4 +lw $ra, 0($sp) +addi $sp, $sp, 4 + +# Clean stack variable space +addi $sp, $sp, 12 +# Return +lw $fp, 0($sp) +addi $sp, $sp, 4 +jr $ra