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]() val paramCounterStack = collection.mutable.Stack[Int]() def eh_param = procStack match { case stack if ! stack.isEmpty => true // stack.top.isInstanceOf[Procedimento] || stack.top.isInstanceOf[Funcao] case _ => false } //PARSER object PascalParser { implicit class isolavel(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 R00"); else Tudo.aplica("DSVS "+Tudo.proc.RotStack.top) nivelLexico+=1 } ) ~ (opt(dec_subrotinas) ^^ { _ => nivelLexico-=1 if (nivelLexico==0) Tudo.aplica("R00: 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 ^^ { foreachExpr }) ~ rep("," ~> (expr_simples ^^ { foreachExpr })) ^^ { mkList } def foreachExpr(o:Object) = { procStack.top.id match { case "write" => fazTudo.aplica("IMPR") case "read" => //ok case _ => } val isByRef = Tudo.isAtArgByRef() inc_pCount // Check for byRef args o match { case s:String => //Okey case o => if ( procStack.top.id=="read" ) assert(false, "Função read recebendo uma expressão!") else if (isByRef) assert(false, "Parametro por referencia recebendo valor! Funcão/procedimento: " + procStack.top.id) //else println("Okey") } o } def inc_pCount { paramCounterStack.push(1+paramCounterStack.pop) } 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.size case p:Procedimento => p.paramInfo.size } def ehProcFun(id:String) = { TabelaSimb.getById(id) match { case Some(e) => e.isInstanceOf[Procedimento] || e.isInstanceOf[Funcao] case None => false } } def assert(bool: => Boolean, errMsg:String) { if ( ! bool ) { println("Erro: " + errMsg) sys.exit(1) } } def entraId(id:String) { if (ehProcFun(id)) { if ( TabelaSimb.getById(id).get.isInstanceOf[Funcao] ) Tudo.aplica("AMEM 1") procStack.push(TabelaSimb.getById(id).get) paramCounterStack.push(0) } else if (id=="write" || id=="read") { procStack.push(new Entrada(id)) paramCounterStack.push(0) id match { case "write" => case "read" => } } } def saiId(id:String) { if (id=="write" || id=="read") { procStack.pop return } if (!procStack.isEmpty && procStack.top.id == "read"){ fazTudo.aplica("LEIT") if (id != "read") fazTudo.atribuicao(id) return } if ( ehProcFun(id) ) { val proc = procStack.pop val nParams = paramCounterStack.pop assert(nParams == getParamsCount(proc), "Número de parametros incorretos na chamada da função/procedimento "+id) } fazTudo.geraMepaDoId(id, nivelLexico) } def chamaId = (ident ^^ { id => entraId(id); id }) <~ opt("(" ~ lista_expr ~ ")") ^^ { id => saiId(id); 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") val pascalSource = ArqExemplos.exemplo8_10 println(parseAll(PascalParser.program, pascalSource)) Tudo.MEPA foreach println // val mp = Tudo.MEPA // val pw = new java.io.PrintWriter(args(1)) // mp foreach pw.println } //TODO: function return as parameter/atribution val noloopPascalProgram = """program exemplo12 (input,output); var x: integer; function p(a:integer; var t: integer):integer; label 200; var a,b:integer; c:integer; procedure q(var a:integer; y:integer); begin q(a,c+b+a+20); write(b,a); read(a,b) end; begin p := p(20,a); t := (23 div (x/2)) + b end; begin x := p(x,x); write(x) end. """ val loopPascalProgram = """program exemplo12 (input,output); var x: integer; function p(var t: integer):integer; label 200; var a,b:integer; c:integer; begin while x>2 do begin x := x+1; p := p(t-10) 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. """ }