Error "Out of segment space" in VMEmulator cause by a getter mwthod in Jack - virtual-machine

I am doing a project for nand2tetris. We write a program in Jack and test it on VMEmulator. The class looks like this:
class List {
field int data;
field List next;
/* Creates a new List object. */
constructor List new(int car, List cdr) {
let data = car;
let next = cdr;
return this;
}
/* Disposes this List by recursively disposing its tail. */
method void dispose() {
if (~(next = null)) {
do next.dispose();
}
// Use an OS routine to recycle the memory held by this object.
do Memory.deAlloc(this);
return;
}
/* Prints the list*/
method void print() {
do Output.printString(" -> ");
do Output.printInt(data);
if (~(next = null)) {
do next.print();
}
return;
}
/* Inserts the argument in the right position of the list (ascending order)*/
method void insertInOrder(int ins){
var List prev, curr, insert;
let prev = this;
let curr = prev.getnext();
while (ins > prev.getdata()){
if (ins < curr.getdata()){
let insert = List.new(ins, curr);
do prev.setnext(insert);
}
else{
let prev = prev.getnext();
let curr = prev.getnext();
}
}
return;
}
/* Searches the argument in the list, if found, it returns the corresponding List object*/
method List find(int toFind){
var List temp;
var List equal;
var boolean found;
let temp = this;
let found = false;
while (~(next = null)){
if(toFind = temp.getdata()){
let equal = temp;
let found = true;
}
let temp = temp.getnext();
}
if (found){
return equal;
}
else{
return null;
}
}
method List getnext(){
return next;
}
method void setnext(List object){
let next = object;
return;
}
method int getdata(){
return data;
}
}
It has one private variable data and a pointer next. So I wrote getter and setter method to return those values. Other methods are fine only the getdata()method is incorrect. When it runs through the VMEmulator, it shows the error Out of segment space in List.getdata.3. This shows in the VMEmulator.
0function List.getdata0
1push argument0
2pop pointer0
3push this 0
4return
the error is at the 4th line return. When I change the Jack code, the same error is still at the 4th line.
What exactly is the problem in my getter method?

When you run a VM program on the VMEmulator you must first manually set the pointers to the various segments, otherwise you may get an "Out of segment space" error.
To understand the necessary settings, look at what the corresponding .tst file does. An alternative method is to insert the proposed code inside a function, since the function call automatically makes this type of setting.

You can get this error when you try to access member data of an object which is not constructed. Could it be that the List cdr in the constructor was not properly constructed?

Related

How do you initialize properties with custom setters that do error checking?

How can I initialize a property with a custom setter?
For example, in my setter I make sure that the value is not negative.
class Foo(length: Int) {
var length = length
set(value) {
if (value < 0) throw IllegalArgumentException("Can't be negative.")
field = value
}
}
}
However if I call it as Foo(-5) the exception doesn't call since setters aren't called when properties are initialized.
Another thing I tried was below, but then it seems wrong to set the length twice.
class Foo(length: Int) {
var length = length
set(value) {
if (value < 0) throw IllegalArgumentException("Can't be negative.")
field = value
}
}
init {
this.length = length
}
}
Finally I thought about the code below, but that seems wrong since you are checking for the wrong value in two spots.
class Foo(length: Int) {
init {
if (length < 0) throw IllegalArgumentException("Can't be negative.")
}
var length = length
set(value) {
if (value < 0) throw IllegalArgumentException("Can't be negative.")
field = value
}
}
}
Your second method is just about as clean as you can make it, although I would set the initial value to some constant like 0 rather than length. Then if you forget to assign length in an init block, you get a compiler warning that the constructor parameter is unused.
There is also a 'fourth' way (variation of your second, actually):
class Foo {
var length = 0 // You cannot even assign length here
set(value) {
if (value < 0) throw IllegalArgumentException("Can't be negative.")
field = value
}
// Having to use a warning suppression is the primary drawback of this 'fourth' way
#Suppress("ConvertSecondaryConstructorToPrimary")
constructor(length: Int) {
this.length = length
}
}
Apart from the express warning suppression annotation, this way the cleanest in my opinion, with no repetition and with minimal boilerplate.

add a object to a array in my class

I want to add an object (from a different class) to an array in my class.
When I try to do that I get this
error: 0xC0000005: Access violation writing location
0x0000000000000000
I create the object (to be added) in the main function and I use the push method in the main function to add this object to my Parking_Lot class.
My code:
void Parking_Lot::push(Cars const &car)
{
time_t t = time(NULL);
struct tm Today = *localtime(&t);
if (is_full())
{
printf("Parking lot is full!!\n");
return;
}
if (Today.tm_hour < OpeningT.tm_hour && Today.tm_hour > ClosingT.tm_hour)
{
printf("Parking lot is now closed!!\n");
printf("Opening time: from %02d:%02d to %02d:%02d\n", OpeningT.tm_hour, OpeningT.tm_min, ClosingT.tm_hour, ClosingT.tm_min);
}
else if (Today.tm_hour == OpeningT.tm_hour || Today.tm_hour == ClosingT.tm_hour)
{
if(Today.tm_min > OpeningT.tm_min || Today.tm_min < ClosingT.tm_min) Lot[front++] = car;
else
{
printf("Parking lot is now closed!!\n");
printf("Opening time: from %02d:%02d to %02d:%02d\n", OpeningT.tm_hour, OpeningT.tm_min, ClosingT.tm_hour, ClosingT.tm_min);
}
}
else if(Today.tm_hour > OpeningT.tm_hour && Today.tm_hour < ClosingT.tm_hour) Lot[front++] = car;
}
where the car is the object I want to add and the Lot is the array in my class that I want to add the object to.
The constructor of my class:
Parking_Lot::Parking_Lot(int s)
{
Cars* Lot = new Cars[s+1];
size = s;
front = 0;
}
What am i doing wrong here and how can I fix it?
The problem is in your constructor:
Parking_Lot::Parking_Lot(int s)
{
Cars* Lot = new Cars[s+1];
size = s;
front = 0;
}
You define a new and separate variable Lot inside the constructor. It will not be related to any possible member variable you might have with the same name.
You need to initialize the member variable instead:
Parking_Lot::Parking_Lot(int s)
{
Lot = new Cars[s+1];
size = s;
front = 0;
}

JavaFX troubles with removing items from ArrayList

I have 2 TableViews (tableProduct, tableProduct2). The first one is populated by database, the second one is populated with selected by user items from first one (addMeal method, which also converts those to simple ArrayList). After adding/deleting few objects user can save current data from second Table to txt file. It seems to work just fine at beginning. But problem starts to show a bit randomly... I add few items, save it, delete few items, save it, everything is fine. Then after few actions like that, one last object stays in txt file, even though the TableView is empty. I just can't do anything to remove it and I get no errors...
Any ideas what's going on?
public void addMeal() {
productData selection = tableProduct.getSelectionModel().getSelectedItem();
if (selection != null) {
tableProduct2.getItems().add(new productData(selection.getName() + "(" + Float.parseFloat(weightField.getText()) + "g)", String.valueOf(Float.parseFloat(selection.getKcal())*(Float.parseFloat(weightField.getText())/100)), String.valueOf(Float.parseFloat(selection.getProtein())*(Float.parseFloat(weightField.getText())/100)), String.valueOf(Float.parseFloat(selection.getCarb())*(Float.parseFloat(weightField.getText())/100)), String.valueOf(Float.parseFloat(selection.getFat())*(Float.parseFloat(weightField.getText())/100))));
productlist.add(new productSimpleData(selection.getName() + "(" + Float.parseFloat(weightField.getText()) + "g)", String.valueOf(Float.parseFloat(selection.getKcal())*(Float.parseFloat(weightField.getText())/100)), String.valueOf(Float.parseFloat(selection.getProtein())*(Float.parseFloat(weightField.getText())/100)), String.valueOf(Float.parseFloat(selection.getCarb())*(Float.parseFloat(weightField.getText())/100)), String.valueOf(Float.parseFloat(selection.getFat())*(Float.parseFloat(weightField.getText())/100))));
}
updateSummary();
}
public void deleteMeal() {
productData selection = tableProduct2.getSelectionModel().getSelectedItem();
if(selection != null){
tableProduct2.getItems().remove(selection);
Iterator<productSimpleData> iterator = productlist.iterator();
productSimpleData psd = iterator.next();
if(psd.getName().equals(String.valueOf(selection.getName()))) {
iterator.remove();
}
}
updateSummary();
}
public void save() throws IOException {
File file = new File("C:\\Users\\Maciek\\Desktop\\test1.txt");
if(file.exists()){
file.delete();
}
FileWriter fw = null;
BufferedWriter bw = null;
try {
fw = new FileWriter(file);
bw = new BufferedWriter(fw);
Iterator iterator;
iterator = productlist.iterator();
while (iterator.hasNext()) {
productSimpleData pd;
pd = (productSimpleData) iterator.next();
bw.write(pd.toString());
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
bw.flush();
bw.close();
}
}
and yeah, I realize addMethod inside if statement looks scary but don't mind it, that part is allright after all...
You only ever check the first item in the productlist list to determine, if the item should be removed. Since you do not seem to write to the List anywhere without doing a similar modification to the items of tableProduct2, you can just do the same in this case.
public void deleteMeal() {
int selectedIndex = tableProduct2.getSelectionModel().getSelectedIndex();
if(selectedIndex >= 0) {
tableProduct2.getItems().remove(selectedIndex);
productlist.remove(selectedIndex);
}
updateSummary();
}
This way you also prevent issues, if there are 2 equal items in the list, which could lead to the first one being deleted when the second one is selected...
and yeah, I realize addMethod [...] looks scary
Yes, it does, so it's time to rewrite this:
Change the properties in productData and productSimpleData to float and don't convert the data to String until you need it as String.
if (selection != null) {
float weight = Float.parseFloat(weightField.getText());
float weight100 = weight / 100;
float calories = Float.parseFloat(selection.getKcal())*weight100;
float protein = Float.parseFloat(selection.getProtein())*weight100;
float carb = Float.parseFloat(selection.getCarb())*weight100;
float fat = Float.parseFloat(selection.getFat())*weight100;
ProductData product = new productData(
selection.getName() + "(" + weight + "g)",
calories,
protein,
carb,
fat);
productlist.add(new productSimpleData(product.getName(), calories, protein, carb, fat));
tableProduct2.getItems().add(product);
}
Also that this kind of loop can be rewritten to an enhanced for loop:
Iterator iterator;
iterator = productlist.iterator();
while (iterator.hasNext()) {
productSimpleData pd;
pd = (productSimpleData) iterator.next();
bw.write(pd.toString());
bw.newLine();
}
Assuming you've declared productlist as List<productSimpleData> or a subtype, you can just do
for (productSimpleData pd : productlist) {
bw.write(pd.toString());
bw.newLine();
}
furthermore you could rely on a try-with-resources to close the writers for you:
try (FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw)){
...
} catch (IOException e) {
e.printStackTrace();
}
Also there is no need to delete the file since java overwrites the file by default and only appends data if you specify this in an additional constructor parameter for FileWriter.

JUnit testing method with assertions

The isSorted() instance method in class A has a bug:
public class A {
private int[] a;
public A(int[] a) { this.a = a; }
/** Return true if this A object contains an array sorted
* in nondecreasing order; else false. */
public boolean isSorted() {
for(int i=1; i<a.length-1; i++) {
if(a[i] < a[i-1]) return false;
}
return true;
}
}
Write a JUnit test method testIsSorted() which will fail because of this bug, but will pass when the bug is fixed.
(Assume that there is no setUp() method defined.)
This is the answer:
public void testIsSorted() {
int[] array = {2, 1};
A haha = new A(array);
assertFalse(haha.isSorted);
}
first of all where is the bug, i cannot seem to located it.
Secondly shoudn't it be assertTrue(haha.isSorted)
because when its assertFalse it will pass because the array is in descending order, therefore the isSorted will return false and assertFalse(false) will return true where-as assertTrue(false) will return false.
The bug is on the line
for(int i=1; i<a.length-1; i++) {
Since array indexes start at 0, the definition of i should be int i=0, not 1. The index 1 points to the second element of the array.
The assertFalse statement checks that the isSorted() method returns false for the given array {2,1}. The isSorted() method checks that no entry is less than the previous one (conversely, each entry is greater than or equal to the previous one). In the example, it will return false, because 2 at index 0 is greater than 1 at index 1. Therefore, the assertFalse is the correct assertion for the case.
You could also test like this (note the reversed order of array).
public void testIsSorted() {
int[] array = {1, 2};
A haha = new A(array);
assertTrue(haha.isSorted());
}

Comment Line Dissapears After Rewriting a Node

I was writing simple refactoring and noticed a strange thing. The comment line before the node I am rewriting disappears after refactoring. Also comments after the node in question are transferred inside the node and break the indentation in the new place. This is very strange and I want to ask if it is a bug in jdt or I did something wrong and oblivious.
For example my code suppose to refactor if-else statements in a way that the shortest branch would appear first.
when I try to refactor this:
// pre
if(a==6) {
a = 5;
return false;
} else {
a++;
}
//post
I get this:
if (!(a==6)) {
a++;
}
//post
else {
a = 5;
return false;
}
The relevant snippet where the refactoring is done:
protected ASTRewrite createRewrite(CompilationUnit cu, SubProgressMonitor pm) {
pm.beginTask("Creating rewrite operation...", 1);
final AST ast = cu.getAST();
final ASTRewrite rewrite = ASTRewrite.create(ast);
cu.accept(new ASTVisitor() {
public boolean visit(IfStatement node) {
if (node.getStartPosition() > selection.getOffset() + selection.getLength() || node.getStartPosition() < selection.getOffset())
return true;
if (node.getElseStatement() == null)
return true;
int thenCount = countNodes(node.getThenStatement());
int elseCount = countNodes(node.getElseStatement());
if(thenCount <= elseCount)
return true;
IfStatement newnode = ast.newIfStatement();
PrefixExpression neg = negateExpression(ast, rewrite, node.getExpression());
newnode.setExpression(neg);
newnode.setThenStatement((org.eclipse.jdt.core.dom.Statement) rewrite.createMoveTarget(node.getElseStatement()));
newnode.setElseStatement((org.eclipse.jdt.core.dom.Statement) rewrite.createMoveTarget(node.getThenStatement()));
rewrite.replace(node, newnode, null);
return true;
}
});
pm.done();
return rewrite;
}
The // pre comment goes away because the parser considers it to be part of the next statement (represented by node), which you replace with newNode. When node goes away, so does the attached comment.
still thinking about why the // post ends up where it does... Try replacing the newNode before setting its then and else statements