diff --git a/src/main/scala/Parser.scala b/src/main/scala/Parser.scala new file mode 100644 index 0000000000000000000000000000000000000000..83e66152a4e5f696fea951bdd949c1c42469a9f8 --- /dev/null +++ b/src/main/scala/Parser.scala @@ -0,0 +1,322 @@ +package other + +import scala.util.parsing.combinator._ +import sun.java2d.pipe.SpanShapeRenderer.Simple +import other.Tudo.rotulos + +class Arith extends JavaTokenParsers { + //CONTROLE etc. + val fazTudo = Tudo + var nivelLexico = 0 + val rotStack = Tudo.proc.RotStack + + val procStack = collection.mutable.Stack[Entrada]() + object paramCounter { + var paramCount = List[Int]() + def get = paramCount.last + def ++ = + if (paramCount.isEmpty) { + println(paramCount) + println("Empty ++ in paramCount") + sys.exit(1) + } else { + if (paramCount.size==1) + paramCount = Nil + else + paramCount = paramCount.init :+ (paramCount.last+1) + println("++") + } + def newCount = { + paramCount = paramCount :+ 0 + println(paramCount) + } + def done = { + println("done") + paramCount match { + case xs if ! xs.isEmpty => + val last = xs.last + if (xs.size==1) paramCount = Nil + else paramCount = xs.init + last + case Nil => + println("Erro done() em paramCounter nulo"); sys.exit(1) + } + } + } + + def eh_param = procStack match { + case stack if ! stack.isEmpty => + stack.top.isInstanceOf[Procedimento] || stack.top.isInstanceOf[Funcao] + case _ => false + } + + //PARSER + object PascalParser { + implicit class isola(s:String) { + def iso = (s + "\\s").r ^^ { _.take(s.size) } + } + + //PROGRAM + def program = { + def programInOut = "(" ~> repsep(ident,",") <~ ")" + fazTudo.iniciaPrograma + "program".iso ~> ident ~ programInOut <~ ";" ~ bloco ~ "." ^^ + { _ => fazTudo.encerraPrograma } + } + def bloco:Parser[Any] = + (opt(dec_rotulos) ~ opt(dec_vars) ^^ + { _ => + if (nivelLexico==0) Tudo.aplica("DSVS R000"); + else Tudo.aplica("DSVS "+Tudo.proc.RotStack.top) + nivelLexico+=1 } ) ~ + (opt(dec_subrotinas) ^^ + { _ => + nivelLexico-=1 + if (nivelLexico==0) Tudo.aplica("R000: NADA") + else + if (Tudo.MEPA.last == "DSVS "+Tudo.proc.RotStack.top) { + //DSVS R003; R003: seguidos! + Tudo.rotulos.-- + Tudo.proc.RotStack.pop() + Tudo.MEPA.remove(Tudo.MEPA.size - 1) + } else + Tudo.aplica(Tudo.proc.RotStack.pop()+": NADA") + } + ) ~ comando_composto + + //ROTULOS + def dec_rotulos = "label".iso ~> """\d+""".r ~ rep("," ~> """\d+""".r) <~ ";" ^^ + { case x~xs => fazTudo.insereRotulos(x::xs, nivelLexico) } + + //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 + 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)} + + 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 + + //COMANDOS + def comando_composto:Parser[Any] = "begin".iso ~ comando ~ rep(";" ~ comando) ~ "end" + def comando = opt("""\d+""".r <~ ":" ^^ { rot => fazTudo.entraRotulo(rot,nivelLexico) }) <~ comando_sem_rotulo + def comando_sem_rotulo:Parser[Any] = desvio | atribuicao | repeticao | + condicional | comando_composto | chamaId | expr_simples + + def atribuicao = ident <~ ":=" ~ expr_simples ^^ + { case id => fazTudo.atribuicao(id) } + + def desvio = "goto".iso ~> """\d+""".r ^^ { rot => fazTudo.gotoRotulo(rot,nivelLexico) } + + def condicional = + ("if".iso ~ boolexpr ^^ { e => + val r = Tudo.rotulos.geraRotulo + Tudo.aplica("DSVF "+r) + rotStack.push(r) + e + }) ~ + "then".iso ~ + (comando_sem_rotulo ^^ { _ => Tudo.aplica(rotStack.pop+": NADA") }) ~ + opt( + ("else".iso ^^ { _ => + val gotoElse = Tudo.MEPA.remove(Tudo.MEPA.size - 1)//.takeWhile {_!=':'} + //rotStack.push(fim_if) + rotStack.push(rotulos.geraRotulo) + Tudo.aplica("DSVS "+rotStack.top) //Vai pro fim do if + Tudo.aplica(gotoElse) + }) + ~ (comando_sem_rotulo ^^ { _ => Tudo.aplica(rotStack.pop+": NADA") }) + ) + + def repeticao = + (("while" ^^ { _=> + val rotLoop = rotulos.geraRotulo + Tudo.aplica(rotLoop+": NADA") + rotStack.push(rotLoop) + }) ~ boolexpr ~ "do" ^^ { _ => + val rotFim = rotulos.geraRotulo + Tudo.aplica("DSVF "+rotFim) + rotStack.push(rotFim) + }) ~ comando_sem_rotulo ^^ { _=> + val rotFim = rotStack.pop + val rotLoop = rotStack.pop + Tudo.aplica("DSVS "+rotLoop) + Tudo.aplica(rotFim+": NADA") + } + + def amem1ForFunctions(id:String) { + val opt = TabelaSimb.getById(id) + opt match { + case Some(fun) if fun.isInstanceOf[Funcao] => Tudo.aplica("AMEM 1") + case _ => //Dont care + } + } + + //EXPRESSOES BOOLEANAS + def boolexpr:Parser[Unit] = + ( + "(" ~> boolexpr_simples ~> rep( ("and"|"or") <~ boolexpr_simples ) <~ ")" | + boolexpr_simples ~> rep ( ("and"|"or") <~ boolexpr ) + ) ^^ + { lst => lst.reverse.foreach { case "and" => fazTudo.aplica("CONJ") + case "or" => fazTudo.aplica("DISJ")} + } + + def boolexpr_simples = + ( + expr_simples ~> relacao <~ expr_simples | + "(" ~ expr_simples ~> relacao <~ expr_simples ~ ")" + ) ^^ + { + case "=" => fazTudo.aplica("CMIG") + case "<>" => fazTudo.aplica("CMDG") + case "<=" => fazTudo.aplica("CMEG") + case ">=" => fazTudo.aplica("CMAG") + case "<" => fazTudo.aplica("CMME") + case ">" => fazTudo.aplica("CMMA") + } + def relacao = "<="|">="|"="|"<>"|"<"|">" + + //EXPRESSOES + def lista_expr = + expr_simples ~ rep("," ~ expr_simples) ^^ + { mkList } + def expr_simples:Parser[Object] = termo ~ rep( ("+"|"-") ~ termo ) ^^ + { + case t ~ lst if ! lst.isEmpty => + lst.reverse.foreach { + case ("+" ~ t) => fazTudo.aplica("SOMA") + case ("-" ~ t) => fazTudo.aplica("SUBT") + case _ => println("op???") + } + new AnyRef + case t ~ Nil => t + } + + def termo = fator ~ rep( ("*"|"div"|"/") ~ fator ) ^^ + { case fat~lst if ! lst.isEmpty => + lst.map{ case ~(str,_) => str }.reverse.foreach { + case "*" => fazTudo.aplica("MULT") + case "div"|"/" => fazTudo.aplica("DIVI") + } + new AnyRef + case fat ~ Nil => fat + } + def fator = ( "("~expr_simples~")" | chamaId | numero ) ^^ { case p:String => p; case _ => new AnyRef} + + def getParamsCount(e:Entrada) = e match { + case f:Funcao => f.paramInfo + case p:Procedimento => p.paramInfo + } + + + def ehProcFun(id:String) = { + TabelaSimb.getById(id) match { + case Some(e) => e.isInstanceOf[Procedimento] || e.isInstanceOf[Funcao] + case None => false + } + } + + var passaId = "" + + def chamaId = + ident <~ opt("(" ~ lista_expr ~ ")") ^^ { id => fazTudo.chamaId(id, nivelLexico); id } + + def numero = wholeNumber ^^ { case x => fazTudo.literal(x.toInt) } + + } +} + +object MyParser extends Arith { + + def main(args: Array[String]) { + if (args.size != 2) { + println("./compilador [ArqEntrada] [NomeArquivoSaida]") + sys.exit(1) + } + val pascalSource = io.Source.fromFile(args(0)).getLines().mkString("\n") + parseAll(PascalParser.program, pascalSource) + val mp = Tudo.MEPA + val pw = new java.io.PrintWriter(args(1)) + mp foreach pw.println + } + + +//TODO: (-x) +//TODO: READ/WRITE COM DOIS PARAMETROS +//TODO: Verificar número correto de parametros ao chamar funcao + +val loopPascalProgram = +"""program exemplo12 (input,output); + var x: integer; + function p(var t: integer):integer; + label 200; + var a,b,c:integer; + begin + while x>2 do begin + x := x+1; + p := p(t,a) + end; + t := x - 20*4 - (23 div (x/2)) + b + end; +begin + x := p(x); + write(x) +end. +""" + +val simplePascalProgram = +"""program exemplo12 (input,output); + var x: integer; + function p(var t: integer):integer; + label 200; + var a,b,c:integer; + begin + 200: if t>3 and (p(x)<4 or t=-1) and t>=1 then + write(t); + read(x); + goto 200; + t := x - 20*4 - (23 div (x/2)) + b; + p := t + end; +begin + x := p(x); + write(x) +end. +""" +val complexPascalProgram = +"""program exemplo12 (input,output); + var x: integer; + procedure p(var t: integer); + label 100,200; + var s : integer; + function f(z:integer):integer; + begin + if z=1 then z:=2; + if z<0 and 10>2 then goto 200 + else if z=0 then f:=2 + else f:=f(z-2)*z+1 + end; + begin + 100: s:=f(t); t:=s; + if t<x then goto 100; + 200: x:=x-1 + end; + procedure r; + procedure q; + var y:integer; + begin read(y); p(y); write(y) end; + begin q end; + begin read(x); r end. +""" + +}