// This file is part of www.nand2tetris.org // and the book "The Elements of Computing Systems" // by Nisan and Schocken, MIT Press. // File name: projects/12/String.jack /** * Represents character strings. In addition for constructing and disposing * strings, the class features methods for getting and setting individual * characters of the string, for erasing the string's last character, * for appending a character to the string's end, and more typical * string-oriented operations. */ class String { field int maxLength; field int length; field Array s; /** constructs a new empty string with a maximum length of maxLength * and initial length of 0. */ constructor String new(int maxStringLength) { let maxLength = maxStringLength; let length = 0; // Only allocate memory for positive length. if (maxLength > 0) { let s = Array.new(maxLength); } else { let s = 0; } return this; } /** Disposes this string. */ method void dispose() { // Only deAlloc for positive length. We do not alloc memory in constructor // if length is not positive. if (~(s = 0)) { do s.dispose(); } return; } /** Returns the current length of this string. */ method int length() { return length; } /** Sets all fields to null and resets length. */ method void clear() { var int i; let i = 0; while (i < maxLength) { let s[i] = 0; let i = i + 1; } let length = 0; return; } /** Returns the character at the j-th location of this string. */ method char charAt(int j) { if (j < maxLength) { return s[j]; } return 0; // Out-of-bounds access. Consider raising an error. } /** Sets the character at the j-th location of this string to c. */ method void setCharAt(int j, char c) { if (j < maxLength) { let s[j] = c; } else { // Out-of-bounds access. Consider raising an error. } return; } /** Appends c to this string's end and returns this string. */ method String appendChar(char c) { if (length < maxLength) { let s[length] = c; let length = length + 1; } return this; } /** Erases the last character from this string. */ method void eraseLastChar() { if (length > 0) { let length = length - 1; let s[length] = 0; } return; } /** Returns the integer value of this string, * until a non-digit character is detected. */ method int intValue() { var int i, result, multiplier; var boolean isNegative, continue; var char c; let i = 0; let isNegative = false; if (charAt(0) = 45) { let isNegative = true; let i = i + 1; } // First iterate up to the highest numerical character. let continue = true; while (continue) { let c = charAt(i); if ((c > 47) & (c < 58)) { let i = i + 1; } else { let continue = false; } if (~(i < maxLength)) { let continue = false; } } // Then iterate backwards and add the values to result. // Checking if we are within the range allows us to not // worry about a potential negative sign. let continue = true; let multiplier = 1; let i = i - 1; while (continue) { let c = charAt(i); if ((c > 47) & (c < 58)) { let result = result + ((c - 48) * multiplier); let multiplier = multiplier * 10; } else { let continue = false; } if (i = 0) { let continue = false; } let i = i - 1; } if (isNegative) { let result = -result; } return result; } /** Sets this string to hold a representation of the given value. */ method void setInt(int val) { var int digit, divisor; var boolean firstDigitPrinted; let divisor = 10000; let firstDigitPrinted = false; do clear(); if (val = 0) { do appendChar(48); // 0 return; } if (val < 0) { do appendChar(45); // 45 = '-' let val = (~val) + 1; } while (~(divisor = 0)) { let digit = val / divisor; if (digit = 0) { if (firstDigitPrinted) { do appendChar(48 + 0); } } else { do appendChar(48 + digit); let firstDigitPrinted = true; } let val = val - (digit * divisor); let divisor = divisor / 10; } return; } /** Returns the new line character. */ function char newLine() { return 128; } /** Returns the backspace character. */ function char backSpace() { return 129; } /** Returns the double quote (") character. */ function char doubleQuote() { return 34; } }