终于来到了Hack计算机架构的最后一部分——操作系统的构建了!这一章的内容涉及了大量的逻辑架构、算法问题与细节处理,需要花很多精力才能够完成。我曾经与nand2tetris团队的一位工作人员有过联系,他就指出,这本书最后几个较难的章节介绍性的内容太少了,最后的OS章节如果作为正常的上课来学习的话,两周时间是绝对不够的(只要想想,计算机专业的学生得花一个学期学OS),其中涉及了太多问题。因此,在这篇文章中,我会将语言规范、溢出处理、特殊情况处理等几个重要的问题单独列出加以讨论。
Math
溢出(overflow)处理:
Math中各个算法的实现其实都不难,重要的是必须考虑溢出情况,因为这是一台16位的计算机,所以它能表示的数字范围在-32768~32767之间。而溢出情况就是指计算的数字超出了这个范围,如果不加以考虑的话,溢出部分的数字会出现混乱。这里,我给大家提供一篇参考文章,里面详细阐述了这方面的内容。
// 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/Math.jack
/**
* A basic math library.
*/
class Math {
/** Initializes the library. */
function void init() {
return;
}
/** Returns the absolute value of x. */
function int abs(int x) {
var int absNum;
if (x < 0){
let absNum = -x;
}
else{
let absNum = x;
}
return absNum;
}
/** Returns the product of x and y. */
function int multiply(int x, int y) {
var int sum;
var int shiftedX,functionY;
var int flag,j;
var boolean WhetherNeg;
let sum = 0;
let shiftedX = Math.abs(x);
let functionY= Math.abs(y);
let flag=1;
let j=0;
if ((x=0)|(y=0)){
return 0;
}
let WhetherNeg = ((x<0)=(y<0));
while(j<16){
if(functionY&flag=flag){
let sum = sum + shiftedX;
}
let shiftedX=shiftedX+shiftedX;
let flag=flag+flag;
let j=j+1;
}
if (~WhetherNeg){
let sum=-sum;
}
return sum;
}
/** Returns the integer part of x/y (x>0,y>0). */
function int div(int x, int y) {
var int q,qy;
if((y<0)|(y>x)){
return 0;
}
let q = Math.div(x,y+y);
let qy = Math.multiply(q,y);
if (x-qy-qy<y){
return q+q;
}
else{
return q+q+1;
}
}
/** Returns the integer part of x/y. */
function int divide(int x, int y) {
var int answer;
var int absX,absY;
var boolean WhetherNeg;
let absX = Math.abs(x);
let absY= Math.abs(y);
if(absY=0){
return Sys.error(3);
}
let WhetherNeg = ((x<0)=(y<0));
let answer = Math.div(absX, absY);
if (~WhetherNeg){
let answer=-answer;
}
return answer;
}
/** Returns to the exponent number n where x <= 2^n. */
function int logTwo(int x){
var int powerTwo,flag;
if ((x>16384)&((x<32767)|(x=32767))){
return 15;
}
let powerTwo = 1;
let flag = 0;
while (powerTwo<x){
let powerTwo = powerTwo+powerTwo;
let flag = flag + 1;
}
return flag;
}
/** Returns to x^y. */
function int power(int x, int y){
var int flag;
var int result;
let flag = y;
let result = 1;
if(y=0){
return 1;
}
while ( flag>0 ){
let result = Math.multiply(result,x);
let flag=flag-1;
}
return result;
}
/** Returns the integer part of the square root of x. */
function int sqrt(int x) {
var int y,j,flag,powerJ;
var int n,halfN;
let y=0;
let n = Math.logTwo(x);
let halfN = Math.divide(n,2);
let j=halfN;
if (x<0){
return Sys.error(3);
}
while (j>-1){
let powerJ = Math.power(2,j);
let flag = y+powerJ;
let flag = Math.multiply(flag,flag);
if (((flag < x) | (flag = x)) & (flag > 0)){
let y = y + powerJ;
}
let j=j-1;
}
return y;
}
/** Returns the greater number. */
function int max(int a, int b) {
if (a>b){
return a;
}
else{
return b;
}
}
/** Returns the smaller number. */
function int min(int a, int b) {
if (a<b){
return a ;
}
else{
return b;
}
}
}
Array
Array模块的实现非常简单,只需要注意,它调用了Memory模块中的相关函数,以实现动态分配内存。
// 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/Array.jack
/**
* Represents an array. Can be used to hold any type of object.
*/
class Array {
/** Constructs a new Array of the given size. */
function Array new(int size) {
var Array a;
let a=Memory.alloc(size);
return a;
}
/** De-allocates the array and frees its space. */
method void dispose() {
do Memory.deAlloc(this);
return;
}
}
String
语言规范:field变量的使用
String的本质是一个数组,在每一个String类中,都必须有四个全局参数,一个是数组a,代表了String的起始地址,一个是当前字符串长度stringLength和最大字符串长度allocLength(注意,这两个长度是不同的!),另外还有判断String是否为负数字符串的negFlag。
负数的处理:
1,String.new(0) 参数小于0时最好报错,参数等于0时,默认给它赋1的空间。
2,数字与字符串相转换时,若数字为负数,需要加符号,这里用negFlag来判别。
此外,本书的字符串编码与ASCII有细微差异,例如,书中将backspace定义为129,换行定义为128,读者只需了解即可。
// 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 a String object. Implements the String type.
*/
class String {
field Array a;
field int stringLength;
field boolean negFlag;
field int allocLength;
/** Constructs a new empty String with a maximum length of maxLength. */
constructor String new(int maxLength) {
if (maxLength<1){
let maxLength = 1;
}
let allocLength = maxLength;
let negFlag = false;
let a = Array.new(maxLength);
let stringLength = 0;
return this;
}
/** De-allocates the string and frees its space. */
method void dispose() {
do a.dispose();
return;
}
/** Returns the current length of this String. */
method int length() {
return stringLength;
}
/** Returns the character at location j. */
method char charAt(int j) {
var char c;
let c=a[j];
return c;
}
/** Sets the j"th character of this string to be c. */
method void setCharAt(int j, char c) {
let a[j]=c;
return;
}
/** Appends the character c to the end of this String.
* Returns this string as the return value. */
method String appendChar(char c) {
var int length;
if(stringLength=allocLength){
do Sys.error(17);
}
let length = stringLength;
let a[len