CS143: Compilation Principle PA1: familiar with Cool language

Simple programming requirements

The requirements of this pa are in handouts / PA1 Pdf. We need to implement a Stack Machine stack machine, which is based on the stack for storage and execution. Here is a brief translation of the description in PDF.

After starting the stack machine, the machine creates a Command line space , a > is displayed on the terminal, and the following instructions can be accepted, which are pushed into the stack.

  • integer
  • Character +, s, e

Enter the character e for the current Stack top instruction Do something.

If the top of the stack is +, the two integers after + and + will pop up, and the result of adding the two integers will be pressed on the stack. We do not consider the case where the two elements after + are not integers and are other instructions.

If the top of the stack is s, pop up s, and then exchange the next two elements in the stack.

If the top of the stack is an integer or the stack is empty, no operation is performed.

Enter the character x to exit the stack machine.

Cool language syntax reminder

In handout, it is suggested that we adopt an object-oriented method to deal with different instructions. Anyway, you should first read the Cool Manual and Cool Tour to understand the basic syntax of the Cool language. Both files are in the handouts directory. I suggest you read through these two PDF files. Later PA also needs a lot of reading and your own research. This is a good opportunity to enter the state! You can practice the very important skills of filtering important information in long text and understanding help documents in a short time,

Here are some points to pay attention to, which are the places where I often make mistakes, while coolc has almost no error prompt, so it's very troublesome to modify grammar errors.

  1. Each class method consists of a expression By definition, this expression may be a variable or a code block {}, and the value of the expression is the return value of the method. Therefore, braces are often contained in braces. Method needs to be added after the closing brace};.
  2. if, while and other structures need to be followed by then, loop and other keywords, not directly with expressions.
  3. if, while and other structures are also expressions with values. When you need to include multiple expressions, use {} code blocks, similar to class methods.
  4. Local variables need to be defined with the let keyword and cannot be defined directly in the code segment.

My realization

Put my paper here stack.cl The code in is for reference only.

First, define Command series classes, which have execute and getchar interfaces to execute instructions and obtain instruction names respectively.

class StackCommand {

   getChar(): String {
      "Called from base class"
   };

   execute(node: StackNode): StackNode {
      let ret: StackNode in {
         (new IO).out_string("Undefined execution!\n");
         ret;
      }
   };

   getNumber(): Int {
      0
   };
};

class IntCommand inherits StackCommand {
   number: Int;

   init(num: Int): SELF_TYPE {
      {
         number <- num;
         self;
      }
   };

   execute(node: StackNode): StackNode {
      node
   };

   getNumber(): Int {
      number
   };

   getChar(): String {
      (new A2I).i2a(number)
   };
};

class PlusCommand inherits StackCommand {
   init(): SELF_TYPE {
      self
   };

   execute(node: StackNode): StackNode {
      let n1: StackNode <- node.getNext(),
         n2: StackNode <- n1.getNext(),
         sum: Int,
         ret: StackNode in {
            if (not (isvoid n1)) then
               if (not (isvoid n2)) then {
                  sum <- n1.getCommand().getNumber() + n2.getCommand().getNumber();
                  ret <- (new StackNode).init((new IntCommand).init(sum), n2.getNext());
               } 
               else 
                  0
               fi
            else
               0
            fi;
            ret;
         }
   };

   getChar(): String {
      "+"
   };
};

class SwapCommand inherits StackCommand {
   init(): SELF_TYPE {
      self
   };

   execute(node: StackNode): StackNode {
      let next: StackNode <- node.getNext().getNext() in {
         node <- node.getNext();
         node.setNext(next.getNext());
         next.setNext(node);
         next;
      }
   };

   getChar(): String {
      "s"
   };
};

The execute interface of the instruction class accepts Stack top As a parameter, returns the new stack top. The stack structure is defined as follows:

class StackNode {
   command : StackCommand;
   next : StackNode;

   init(co: StackCommand, ne: StackNode): StackNode {
      {
         command <- co;
         next <- ne;
         self;
      }
   };

   putOnTop(co: StackCommand): StackNode {
      let newNode: StackNode in {
         newNode <- (new StackNode).init(co, self);
         newNode;
      }
   };

   getCommand(): StackCommand {
      {
         command;
      }
   };

   getNext(): StackNode {
      {
         next;
      }
   };

   setNext(node: StackNode): StackNode {
      next <- node
   };
};

With these foundations, implement the main process in the main class. The main function continuously waits for the command line input to process the obtained character instructions.

class Main inherits A2I {
   stackTop: StackNode;

   printStack(): Object {
      let node: StackNode <- stackTop in {
         while (not (isvoid node)) loop
         {
            (new IO).out_string(node.getCommand().getChar());
            (new IO).out_string("\n");
            node <- node.getNext();
         }
         pool;
      }
   };

   pushCommand(command: StackCommand): StackCommand {
      {
         if (isvoid stackTop) then {
            let nil: StackNode in {
               stackTop <- (new StackNode).init(command, nil);
            };
         } else {
            stackTop <- stackTop.putOnTop(command);
         } fi;
         command;
      }
   };

   executeStackMachine(inString: String): Object {
      {
         if (inString = "+") then
         {
            pushCommand((new PlusCommand).init());
         }
         else
            if (inString = "s") then
               pushCommand((new SwapCommand).init())
            else
               if (inString = "d") then
                  printStack()
               else
                  if (inString = "x") then
                     -- stop
                     {
                        (new IO).out_string("stop!\n");
                        abort();
                     }
                  else
                     if (inString = "e") then
                        let node: StackNode <- stackTop in {
                           if (not (isvoid node)) then
                              stackTop <- node.getCommand().execute(node)
                           else
                              0
                           fi;
                        }
                     else
                        pushCommand((new IntCommand).init((new A2I).a2i(inString)))
                     fi
                  fi
               fi
            fi
         fi;
      }
   };

   main() : Object {
      let inString: String in {
         while (true) loop
         {
            (new IO).out_string(">");
            inString <- (new IO).in_string();
            executeStackMachine(inString);
         }
         pool;
      }
   };

};

Let the Cool program run

It is not recommended to use the well provided make test test test, because this instruction will stack The characters in test are crammed into our program, which may cause format confusion.

I added a new item to this Makefile:

run: compile
	${CLASSDIR}/bin/spim -file stack.s

This is to run our program conveniently. After running, you can play with the stack machine written by yourself. I will stack The instructions in test are called to the stack machine in turn, and the results are as follows. You can also play with others, which is very interesting.

../../bin/spim -file stack.s
SPIM Version 6.5 of January 4, 2003
Copyright 1990-2003 by James R. Larus (larus@cs.wisc.edu).
All Rights Reserved.
See the file README for a full copyright notice.
Loaded: ../lib/trap.handler
>e
>e
>1
>+
>2
>s
>d
s
2
+
1
>e
>d
+
2
1
>e
>+
>1
>s
>s
>s
>d
s
s
s
1
+
3
>e
>e
>s
>e
>e
>e
>d
4
>x
stop!
Abort called from class Main

This concludes the simple and brief PA1.

Added by LacOniC on Thu, 09 Dec 2021 10:02:33 +0200