Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grupo 09 - Mudanças no Interpreter para adicionar suporte a Ponteiros e Records #156

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ object JimpleCodeGenerator extends CodeGenerator[ClassDeclaration] {
case _ => throw new Exception("Record must be a field reference.")
}

case PointerAssignment(_) =>
case PointerAssignment(_, _) =>
throw new Exception(
"Pointers are not yet supported by Jimple code generation."
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ object TACodeGenerator extends CodeGenerator[List[TAC]] {
val (i, insts3) = generateExpression(index, insts2)
return insts3 :+ ListSet(t, i, a, "")

case PointerAssignment(pointerName) =>
case PointerAssignment(pointerName, _) =>
val p = Name(pointerName, LocationType)
return insts1 :+ SetPointer(t, p, "")

Expand Down
117 changes: 106 additions & 11 deletions src/main/scala/br/unb/cic/oberon/environment/Environment.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package br.unb.cic.oberon.environment

import br.unb.cic.oberon.ir.ast.{Expression, Location, Procedure, ReferenceToUserDefinedType, Statement, Type, UserDefinedType}
import br.unb.cic.oberon.ir.ast.{ArrayType, ArrayValue, BaseLocation, Expression, Location, NullLocation, NullType, NullValue, Procedure, RecordType, ReferenceToUserDefinedType, Statement, Type, Undef, UserDefinedType, VariableDeclaration}
import org.jline.builtins.Completers.CompletionEnvironment

import scala.collection.mutable.{Map, Stack}
import scala.collection.mutable.{ListBuffer, Map, Stack}

case class MetaStmt(f: Environment[Expression] => Statement) extends Statement

Expand All @@ -30,9 +30,9 @@ class Environment[T](private val top_loc:Int = 0,

def setGlobalVariable(name: String, value: T): Environment[T] = {
return new Environment[T](top_loc = this.top_loc+1,
locations = this.locations+(Location(top_loc)-> value),
global = this.global+(name -> Location(top_loc)) ,
procedures = this.procedures,
locations = this.locations+(BaseLocation(top_loc)-> value),
global = this.global+(name -> BaseLocation(top_loc)) ,
procedures = this.procedures,
userDefinedTypes = this.userDefinedTypes,
stack = this.stack
)
Expand All @@ -47,7 +47,6 @@ class Environment[T](private val top_loc:Int = 0,
stack = this.stack)
}


def setParameterReference(name: String, loc: Location): Environment[T] = {
//stack.top += name -> loc
val copyStack = stack.clone()
Expand All @@ -61,7 +60,6 @@ class Environment[T](private val top_loc:Int = 0,
stack = copyStack)
}


def setLocalVariable(name: String, value: T) : Environment[T] = {
// top_loc += 1
// if(stack.isEmpty) {
Expand All @@ -73,16 +71,15 @@ class Environment[T](private val top_loc:Int = 0,
if(copyStack.isEmpty) {
copyStack.push(Map.empty[String, Location])
}
copyStack.top.addOne(name -> Location(top_loc))
copyStack.top.addOne(name -> BaseLocation(top_loc))
new Environment[T](top_loc = this.top_loc+1,
locations = this.locations.addOne(Location(top_loc) -> value),
locations = this.locations.addOne(BaseLocation(top_loc) -> value),
global = this.global,
procedures = this.procedures,
userDefinedTypes = this.userDefinedTypes,
stack = copyStack)
}


def setVariable(name: String, value: T) : Environment[T] = {
if(stack.nonEmpty && stack.top.contains(name)) {
val newlocations = locations.clone()
Expand Down Expand Up @@ -129,7 +126,6 @@ class Environment[T](private val top_loc:Int = 0,
def lookupUserDefinedType(name: String): Option[UserDefinedType] =
userDefinedTypes.get(name)


def declareProcedure(procedure: Procedure): Environment[T] = {
//Unit = procedures(procedure.name) = procedure
val copyprocedures = procedures.clone() + (procedure.name -> procedure)
Expand Down Expand Up @@ -195,5 +191,104 @@ class Environment[T](private val top_loc:Int = 0,
}
else throw new RuntimeException("Variable " + name + " is not defined")
}

def declareGlobalPointer(pointerName: String, variableType: Type, baseValueForRecords: T): Environment[T] = {

var newGlobal = global.clone();
var newLocations = locations.clone();
var topLoc = this.top_loc;

variableType match {
case ReferenceToUserDefinedType(name) => {

var userDefinedType = this.userDefinedTypes(name);

userDefinedType.baseType match {
case RecordType(fields) => {
fields.foreach {
case VariableDeclaration(name, variableType) => {
newGlobal += (getNameForRecordField(pointerName, name) -> BaseLocation(topLoc))
newLocations += (BaseLocation(topLoc) -> baseValueForRecords)
topLoc += 1
}
case _ => {
throw new RuntimeException("Unknown field type");
}
};
} case _ => {
newGlobal(pointerName) = NullLocation;
}
}
} case _ => {
newGlobal(pointerName) = NullLocation;
}
}

return new Environment[T](
top_loc = topLoc,
locations = newLocations,
global = newGlobal,
procedures = this.procedures,
userDefinedTypes = this.userDefinedTypes,
stack = this.stack
)

}

def createLocationForGlobalPointer(name: String, value: T): Environment[T] = {

if(!global.contains(name)) {
throw new RuntimeException("Variable " + name + " is not defined")
}

val newGlobal = global.clone()
newGlobal(name) = BaseLocation(this.top_loc)

val newLocations = locations.clone()
newLocations(BaseLocation(this.top_loc)) = value

return new Environment[T](top_loc = this.top_loc + 1,
locations = newLocations,
global = newGlobal,
procedures = this.procedures,
userDefinedTypes = this.userDefinedTypes,
stack = this.stack
)

}

def setGlobalPointer(name: String, value: Location): Environment[T] = {
if(!global.contains(name)) {
throw new RuntimeException("Variable " + name + " is not defined")
}

val newGlobal = global.clone()
newGlobal(name) = value

new Environment[T](
top_loc = this.top_loc,
locations = this.locations,
global = newGlobal,
procedures = this.procedures,
userDefinedTypes = this.userDefinedTypes,
stack = this.stack
)

}

def dfs(indirections: Int, loc: Location): Location = {
var tmp_loc = loc
var tmp_indirections = indirections
while (tmp_indirections > 1 && locations(tmp_loc).isInstanceOf[Location]) {
tmp_loc = locations(tmp_loc).asInstanceOf[Location]
tmp_indirections = tmp_indirections - 1
}
tmp_loc
}

def getNameForRecordField(recordName: String, field: String): String = {
return recordName + "." + field;
}

}

53 changes: 51 additions & 2 deletions src/main/scala/br/unb/cic/oberon/interpreter/Interpreter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def runInterpreter(module: OberonModule): Environment[Expression] = {
def declareVariable(environment : Environment[Expression], variable: VariableDeclaration): Environment[Expression] = {
environment.baseType(variable.variableType) match {
case Some(ArrayType(length, baseType)) => environment.setGlobalVariable(variable.name, ArrayValue(ListBuffer.fill(length)(Undef()), ArrayType(length, baseType)))
case Some(PointerType(variableType)) => environment.declareGlobalPointer(variable.name, variableType, NullValue)
case _ => environment.setGlobalVariable(variable.name, Undef())
}
}
Expand Down Expand Up @@ -100,8 +101,8 @@ def runInterpreter(module: OberonModule): Environment[Expression] = {
designator match {
case VarAssignment(name) => envt = envt.setVariable(name, evalExpression(envt, exp)._2)
case ArrayAssignment(array, index) => envt = arrayAssignment(envt, array, index, exp)
case RecordAssignment(_, _) => ???
case PointerAssignment(_) => ???
case PointerAssignment(pointerName, indirections) => envt = pointerAssignment(envt, pointerName, exp, indirections)
case RecordAssignment(record, field) => envt = recordAssignment(envt, record, field, exp)
}
envt

Expand Down Expand Up @@ -168,6 +169,12 @@ def runInterpreter(module: OberonModule): Environment[Expression] = {

case ProcedureCallStmt(name, args) =>
callProcedure(name, args, envt)


case NewStmt(name) => {
envt.createLocationForGlobalPointer(name, NullValue)
}

}
}

Expand Down Expand Up @@ -225,6 +232,41 @@ def runInterpreter(module: OberonModule): Environment[Expression] = {
environment
}

def pointerAssignment(envt: Environment[Expression], pointerName: String, exp: Expression, indirections: Int): Environment[Expression] = {

exp match {
case VarExpression(name) => {
val loc = envt.pointsTo(name)
envt.setGlobalPointer(pointerName, envt.dfs(indirections, loc.get))
} case _ => {

envt.pointsTo(pointerName).get match {
case BaseLocation(loc) => {
val value = evalExpression(envt, exp)._2
envt.setVariable(pointerName, value)
} case NullLocation => {
throw new RuntimeException("Pointer " + pointerName + " is null")
} case _ => {
throw new RuntimeException("Unexpected location type")
}
}


}
}
}

def recordAssignment(envt: Environment[Expression], record: Expression, field: String, exp: Expression): Environment[Expression] = {
val value = evalExpression(envt, exp)._2

record match {
case VarExpression(name) => {
envt.setVariable(envt.getNameForRecordField(name, field), value)
}
}

}

/*
* This method is mostly useful for testing purposes.
* That is, here we are considering testability a
Expand Down Expand Up @@ -272,6 +314,13 @@ def runInterpreter(module: OberonModule): Environment[Expression] = {
case AndExpression(left, right) => binExpression(environment, left, right, (v1: Value, v2: Value) => BoolValue(v1.value.asInstanceOf[Boolean] && v2.value.asInstanceOf[Boolean]))
case OrExpression(left, right) => binExpression(environment, left, right, (v1: Value, v2: Value) => BoolValue(v1.value.asInstanceOf[Boolean] || v2.value.asInstanceOf[Boolean]))
case FunctionCallExpression(name, args) => evalFunctionCall(environment, name, args)
case FieldAccessExpression(exp, field) => {
exp match {
case VarExpression(recordName) => {
(environment, environment.lookup(environment.getNameForRecordField(recordName, field)).get)
}
}
}
// TODO FieldAccessExpression
// TODO PointerAccessExpression
}
Expand Down
6 changes: 4 additions & 2 deletions src/main/scala/br/unb/cic/oberon/ir/ast/OberonModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ case object NullValue extends Value {
def value: T = ()
}

case class Location(loc: Int) extends Expression
sealed trait Location extends Expression
case class BaseLocation(loc: Int) extends Location
case object NullLocation extends Location
case class Brackets(exp: Expression) extends Expression
case class ArrayValue(value: ListBuffer[Expression], arrayType: ArrayType)
extends Value { type T = ListBuffer[Expression] }
Expand Down Expand Up @@ -277,7 +279,7 @@ case class ArrayAssignment(array: Expression, index: Expression)
extends Designator
case class RecordAssignment(record: Expression, field: String)
extends Designator
case class PointerAssignment(pointerName: String) extends Designator
case class PointerAssignment(pointerName: String, indirections: Int = 1) extends Designator

/** User defined types.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ trait StatementParser extends ExpressionParser {
| expressionParser ~ ("." ~> identifier) ^^ { case a ~ b =>
RecordAssignment(a, b)
}
| identifier <~ "^" ^^ PointerAssignment
| identifier <~ "^" ^^ (id => PointerAssignment(id, 1))
| identifier ^^ VarAssignment
)

Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/br/unb/cic/oberon/repl/OberonEngine.scala
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ class OberonEngine extends ScriptEngine {
// TODO: Other types of assignment
case ArrayAssignment(_, _) => ???
case RecordAssignment(_, _) => ???
case PointerAssignment(_) => ???
case PointerAssignment(_, _) => ???
case VarAssignment(name) =>
put(name, exp)
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/br/unb/cic/oberon/tc/TypeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ class TypeChecker {

private def checkAssignment(stmt: Statement): T = stmt match {
case AssignmentStmt(VarAssignment(v), exp) => checkVarAssigment(v, exp)
case AssignmentStmt(PointerAssignment(p), exp) => checkPointerAssigment(p, exp)
case AssignmentStmt(PointerAssignment(p, _), exp) => checkPointerAssigment(p, exp)
case AssignmentStmt(ArrayAssignment(arr, element), exp) => checkArrayAssigment(arr, element, exp)
case AssignmentStmt(RecordAssignment(record, field), exp) => checkRecordAssigment(record, field, exp)
}
Expand Down
15 changes: 0 additions & 15 deletions src/test/resources/Pointers/pointerAssigner3.oberon

This file was deleted.

12 changes: 12 additions & 0 deletions src/test/resources/pointers/pointerAssign0.oberon
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
MODULE pointerAssign;

VAR
a : POINTER TO INTEGER;
b : INTEGER;

BEGIN
a^ := b;
b := 5
END

END pointerAssign.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ VAR
e : POINTER TO STRING;

BEGIN
NEW(a);
NEW(b);
NEW(c);
NEW(d);
NEW(e);
a^ := 1;
b^ := 9.5;
c^ := 'c';
Expand Down
13 changes: 13 additions & 0 deletions src/test/resources/pointers/pointerAssign2.oberon
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
MODULE pointerAssign;

VAR
a : POINTER TO REAL;
b : POINTER TO POINTER TO REAL;

BEGIN
NEW(a);
a^ := 10.5;
b^ := a
END

END pointerAssign.
13 changes: 13 additions & 0 deletions src/test/resources/pointers/pointerAssign3.oberon
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
MODULE pointerAssign;

VAR
a : POINTER TO REAL;
b : POINTER TO POINTER TO REAL;

BEGIN
NEW(a);
b^ := a;
a^ := 10.5
END

END pointerAssign.
Loading