From 4dc0ee36d7cdf057c96a25bc02b55d7fc057173e Mon Sep 17 00:00:00 2001
From: ls12 5o Andar <ls12@inf.ufpr.br>
Date: Wed, 17 Jun 2015 14:21:30 -0300
Subject: [PATCH] Add type support! (Tested)

---
 src/main/scala/other/Parser.scala     | 41 ++++++++----
 src/main/scala/other/TabelaSimb.scala | 11 ++++
 src/main/scala/other/Tudo.scala       | 89 +++++++++++++++++++--------
 3 files changed, 104 insertions(+), 37 deletions(-)

diff --git a/src/main/scala/other/Parser.scala b/src/main/scala/other/Parser.scala
index e108459..525cc6b 100644
--- a/src/main/scala/other/Parser.scala
+++ b/src/main/scala/other/Parser.scala
@@ -5,6 +5,9 @@ import sun.java2d.pipe.SpanShapeRenderer.Simple
 import other.Tudo.rotulos
 import com.sun.org.apache.xml.internal.serializer.ToStream.BoolStack
 
+case class ids_t(ids:List[String], tipo: String)
+case class dec_param(byRef:Boolean, ids:List[String], tipo:String)
+    
 class Arith extends JavaTokenParsers {
   //CONTROLE etc.
   val fazTudo = Tudo
@@ -40,11 +43,19 @@ class Arith extends JavaTokenParsers {
     }
     
     def bloco:Parser[Any] =
-        (opt(dec_rotulos) ~ opt(dec_vars) ^^ 
+        (opt(dec_rotulos) ~
+            (opt(dec_tipos) ^^ {
+              case Some(tipos) =>
+                //Add to table
+                TabelaSimb.insere(tipos.map{ t => Tipo(t) })
+              case None => //fine
+            })~
+            opt(dec_vars) ^^ 
             { _ => 
               if (nivelLexico==0) Tudo.aplica("DSVS R00");
               else Tudo.aplica("DSVS "+Tudo.proc.RotStack.top)
-              nivelLexico+=1 } ) ~
+              nivelLexico+=1 
+        }) ~
         (opt(dec_subrotinas) ^^ 
           { _ => 
             nivelLexico-=1
@@ -63,25 +74,31 @@ class Arith extends JavaTokenParsers {
     //ROTULOS
     def dec_rotulos = "label".iso ~> """\d+""".r ~ rep("," ~> """\d+""".r) <~ ";" ^^
       { case x~xs => fazTudo.insereRotulos(x::xs, nivelLexico) }
+   
+    //TIPOS
+    def dec_tipos = "type".iso ~> (def_tipo <~ ";") ~  rep(def_tipo <~ ";" ) ^^ { mkList }
+    
+    def def_tipo = ident <~ "=" ~ "integer"
+    
+    def tipo = ident
     
     //VARIAVEIS
     def dec_vars = "var".iso ~> dec_var ~ rep(";" ~> dec_var) <~ ";" ^^
-      { case xs~xss => fazTudo.insereIntVars(xs ::: xss.flatten, nivelLexico) } 
-    def dec_var  = lista_ident <~ ":" ~ tipo
+      { case xss => fazTudo.insereIntVars(mkList(xss), nivelLexico) } 
+    def dec_var  = (lista_ident <~ ":") ~ tipo ^^ { case ids ~ t => ids_t(ids, t)}
     def lista_ident = ident ~ rep( "," ~> ident ) ^^ { mkList }
-    def tipo = "integer"
     
     //SUB-ROTINAS
     def dec_subrotinas = rep( (dec_proc | dec_func) <~ bloco ~ ";" ^^ 
         {  e => fazTudo.proc.saiProcFunc(nivelLexico); e} )
     
     def dec_proc = "procedure".iso ~> ident ~ opt(params_formais) <~ ";" ^^
-      { case id ~ lstOptIds => fazTudo.proc.entraProc(id, lstOptIds, nivelLexico) }
-    def dec_func = "function".iso  ~> ident ~ opt(params_formais) <~ ":" ~ tipo ~ ";" ^^
-      { case id ~ lstOptIds => fazTudo.proc.entraFunc(id, lstOptIds, nivelLexico) }
+      { case id ~ lstDecParam => fazTudo.proc.entraProc(id, lstDecParam, nivelLexico) }
+    def dec_func = "function".iso  ~> ident ~ opt(params_formais) ~ (":" ~> tipo) <~ ";" ^^
+      { case id ~ lstDecParam ~ tipo => fazTudo.proc.entraFunc(id, lstDecParam, nivelLexico, tipo) }
     
-    def params_formais = "(" ~> params ~ rep(";" ~> params) <~ ")" ^^ { s_xs => mkList(s_xs).map{case opt~id=>(opt,id)}}
-    def params = opt("var".iso) ~ lista_ident <~ ":" ~ tipo
+    def params_formais = "(" ~> params ~ rep(";" ~> params) <~ ")" ^^ { mkList }
+    def params = opt("var".iso) ~ lista_ident ~ (":" ~> tipo) ^^ { case v ~ ids ~ tipo => dec_param(v.isDefined, ids, tipo)}
     
     //COMANDOS
     def comando_composto:Parser[Any] = "begin".iso ~ comando ~ rep(";" ~ comando) ~ "end"
@@ -389,15 +406,13 @@ object MyParser extends Arith {
       sys.exit(1)
     }
     val pascalSource = io.Source.fromFile(args(0)).getLines().mkString("\n")
-//    val pascalSource = ArqExemplos.p
     try 
       println(parseAll(PascalParser.program, pascalSource))
     catch { case e : Exception => println("Erro no programa"); sys.exit(1) }
     val mp = Tudo.MEPA
-//    mp foreach println
     val pw = new java.io.PrintWriter("MEPA")
     mp foreach pw.println
-    pw.close
+    pw.close  
   }
   
 
diff --git a/src/main/scala/other/TabelaSimb.scala b/src/main/scala/other/TabelaSimb.scala
index 8946515..b71fb39 100644
--- a/src/main/scala/other/TabelaSimb.scala
+++ b/src/main/scala/other/TabelaSimb.scala
@@ -9,6 +9,7 @@ case class Procedimento(override val id:String, paramInfo:List[Param],
 case class Param(override val id:String, desloc: Int, byRef:Boolean, nvLex:Int, tipo:String = "integer") extends Entrada(id)
 case class Var(override val id:String, desloc: Int, nvLex:Int, tipo:String = "integer") extends Entrada(id)
 case class Label(override val id:String, rotulo:String, nvLex:Int, var used:Boolean = false, var put:Boolean = false) extends Entrada(id)
+case class Tipo(override val id:String) extends Entrada(id)
 
 object TabelaSimb {
   
@@ -45,6 +46,16 @@ object TabelaSimb {
     }
   }
   
+  def existeTipo(tipo:String):Boolean = {
+    if (tipo == "integer") return true
+    table.exists { e => e match {
+      case t:Tipo =>
+        if (t.id == tipo) true
+        else false
+      case _ => false
+    }}
+  }
+  
   @tailrec
   def numVarsLocais(nvLex:Int, count:Int=0, rest:List[Entrada] = table):Int = rest match {
     case (v:Var) :: xs => numVarsLocais(nvLex, count+1, xs)
diff --git a/src/main/scala/other/Tudo.scala b/src/main/scala/other/Tudo.scala
index fc648f1..bcf6dda 100644
--- a/src/main/scala/other/Tudo.scala
+++ b/src/main/scala/other/Tudo.scala
@@ -15,25 +15,47 @@ object Tudo {
           num match {
             case dig if num<10  => "0"+dig
             case dezena if num<100 => ""+dezena
-            case bigger if num>=100 => "" + bigger
+            case maior if num>=100 => "" + maior
           }
        )
     }
   }
   
-  def insereIntVars(vars: List[String], nivelLexico: Int) = {
-    val orgSize = vars.size
+  def insereIntVars(vars_t: List[ids_t], nivelLexico: Int) = {
+    
+    //Garante que os tipos existem
+    val lst_tipos = vars_t.map { case ids_t(_,t) => t }
+    val tipo_invalido = lst_tipos.distinct.find { t => ! TabelaSimb.existeTipo(t) } //Ache um que não existe
+    
+    tipo_invalido match {
+      case Some(invalido) => //Erro
+        println("Erro: Tipo não declarado na declaração de variáveis: "+invalido)
+        sys.exit(1)
+      case None => //Ok
+    }
+    //end
+    
+    //Garante nenhuma repetição de id
+    val listaIds = vars_t.map{ case ids_t(ids,_) => ids }.flatten
+    val totalAMEM = listaIds.size
+    
+    if (listaIds.distinct.size != listaIds.size) {
+        println("Erro: declaração de variáveis:")
+        println("  identificadores já declarados para parametros ou var: "+
+            listaIds.diff(listaIds.distinct).mkString(" "))
+        sys.exit(1)
+    }
+    //end
+    
     var desloc = 0
-    if (orgSize == vars.distinct.size) {
-      TabelaSimb insere vars.map { id => 
-        val v = Var(id, desloc, nivelLexico); desloc += 1; v
-      } 
-      aplica("AMEM " + orgSize)
-    } else {
-      println("Erro: declaração de variáveis:")
-      println("  identificadores já declarados para parametros ou var: "+vars.diff(vars.distinct).mkString(" "))
-      sys.exit(1)
+    vars_t.foreach { case ids_t(varsId,tipo) =>
+        TabelaSimb insere varsId.map { id =>
+            desloc += 1
+            Var(id, desloc-1, nivelLexico,tipo)
+        }
     }
+    aplica("AMEM " +totalAMEM)
+    
   }
 
   def geraMepaDoId(id: String, nvLexAtual:Int): Unit =
@@ -105,7 +127,7 @@ object Tudo {
       val rotulo = rotulos.geraRotulo //rotuloEntrada
       val rotuloBegin = rotulos.geraRotulo
       RotStack.push(rotuloBegin) //Begin
-      if (nivelLexico>1) {
+      if (nivelLexico>1) { 
         val rotDesvio = TabelaSimb.getLastProc(nivelLexico-1) match {
           case p:Procedimento => p.rotEntrada
           case f:Funcao => f.rotEntrada
@@ -116,10 +138,10 @@ object Tudo {
       rotulo
     }
     
-    def entraProc(id:String, params:Option[ List[(Option[String],List[String])] ], nivelLexico:Int): Unit = {
+    def entraProc(id:String, dec_ps: Option[List[dec_param]], nivelLexico:Int): Unit = {
       val rotulo = entraProcFun(nivelLexico)
       
-      params match {
+      dec_ps match {
         case Some( lstParams ) if ! lstParams.isEmpty =>
           val ps = retornaParamsLst(lstParams, nivelLexico)
           TabelaSimb.insere( Procedimento(id, ps, nivelLexico, rotulo) )
@@ -135,14 +157,19 @@ object Tudo {
       }
     }
     
-    def entraFunc(id:String, params:Option[ List[(Option[String],List[String])] ], nivelLexico:Int):Unit = {
+    def entraFunc(id:String, dec_ps: Option[List[dec_param]],nivelLexico:Int, tipo:String):Unit =
+    {
       val rotulo = entraProcFun(nivelLexico)
-      
-      params match {
+      if ( ! TabelaSimb.existeTipo(tipo) ){
+        
+      }
+     
+       
+      dec_ps match {
         case Some( lstParams ) if ! lstParams.isEmpty =>
           val ps = retornaParamsLst(lstParams, nivelLexico)
           val desloc = -4-ps.size
-          TabelaSimb.insere( Funcao(id,ps,desloc,nivelLexico,rotulo) )
+          TabelaSimb.insere( Funcao(id,ps,desloc,nivelLexico,rotulo,tipo) )
           ps.foreach { param =>
             if (TabelaSimb.temParamOuVarComMesmoId(param.id)) {
               println("Erro: Parâmetros com mesmo nome na função "+id+": "+ param.id)
@@ -155,14 +182,26 @@ object Tudo {
       }
     }
     
-    def retornaParamsLst(params:List[(Option[String],List[String])], nivelLexico:Int):List[Param] =  {
-      var desloc = -3 - params.map(_._2.size).sum
+    def retornaParamsLst(params:List[dec_param], nivelLexico:Int):List[Param] =  {
+      var desloc = - 3 - params.map{ _.ids.size }.sum
+      
+      //Verifica tipos
+      var todosTipos = params.map{ _.tipo }.distinct
+      val invalido = todosTipos.find { t => ! TabelaSimb.existeTipo(t) }
+      
+      invalido match {
+        case Some(inv) => //Erro
+          println("Erro: Tipo não declarado na declaração de parametros: "+inv)
+          sys.exit(1)
+        case None => //Ok
+      }
+      //end
+      
       params.flatMap {
-        case (varOpt, idlst) => 
+        case dec_param(byRef, idlst, tipo) => 
           idlst map { id =>
-            val p = Param(id,desloc,varOpt.isDefined,nivelLexico)
             desloc +=1
-            p
+            Param(id,desloc-1,byRef,nivelLexico,tipo)
           }
       }
     }
@@ -172,6 +211,7 @@ object Tudo {
         case v:Var => TabelaSimb.drop; contaVariaveis(nvLex,count+1)
         case p:Procedimento => if (p.nvLex>nvLex) {TabelaSimb.drop; contaVariaveis(nvLex,count)} else count
         case f:Funcao => if (f.nvLex>nvLex) {TabelaSimb.drop; contaVariaveis(nvLex,count)} else count
+        case t:Tipo => TabelaSimb.drop; contaVariaveis(nvLex,count)
         case r:Label =>
           if (! r.used) {println("Warning: rótulo nunca usado: "+ r.id)}
           TabelaSimb.drop
@@ -192,6 +232,7 @@ object Tudo {
           table.dropWhile {
             case p:Procedimento => if (p.nvLex>nivelLexico) true else false
             case f:Funcao       => if (f.nvLex>nivelLexico) true else false
+            case t:Tipo         => true
             case r:Label =>
               if (r.used) { //Se rótulo nunca usado
                 println("Warning: rótulo nunca usado: "+ r.id)
-- 
GitLab