// Lab Problem 5A - file "machine5a.h" // SE307 CCT // T Naughton, CS NUIM, tomn@cs.may.ie // Last updated 1 November 2000 #include #include #include #include "machinebase.h" // direct base class for this machine #include "varlist.h" // class to keep track of var.s' values #ifndef MACHINE5A_H #define MACHINE5A_H /* This class describes a machine that analyses the code of ** another machine passed to it as input. ** The machine assumes that inputs are syntactically correct and ** follow the restricted format defined in the lab sheets. ** ** The particular analysis performed is determined by the ** ProcessingDeclaration() and ProcessStatement() methods. ** In this machine, these methods perform a simulation of the ** input machine, updating variables' values as needed. ** The machine keeps track of nested loops in the input machine's ** code through recursion so that it knows when the final ** `}' symbol has been reached. It demonstrates this by `pretty ** printing' statements as they are simulated. ** ** This machine extends MachineBase. As of October 2000 the ** code resides at http://www.cs.may.ie/~tnaughton/ ** at the link for course SE307 Computational Complexity Theory. */ class MachineFiveA : public MachineBase { /* This class defines a machine that reads a description of ** another machine (a program following the format described ** in the lab sheets) and performs some analysis on it. The ** result of the analysis is a simple true/false answer. */ /* The following protected data members are from MachineBase: ** char b - input buffer ** ifstream machin - stream object to read from file ** bool analysis - the result of the analysis ** ** The following public methods are from MachineBase: ** bool Analyse() - analyse the input machine in some way ** ** The following protected methods are from MachineBase: ** string Spaces(int) - create blanks for indendation ** string ReadUntil(char) - read from machin until a particular ** character is encountered ** void JumpEndBlock() - reposition file pointer at end of ** current block */ /* ** Data members: public, protected, and private */ protected: VarList vars; // list of variables in input machine code /* ** Member functions: public, protected, and private */ public: MachineFiveA(string fname); // constructor virtual ~MachineFiveA(); // destructor private: virtual void ProcessDeclaration(); // process a declaration virtual void ProcessStatement(int level); // process a statement }; MachineFiveA::MachineFiveA(string fname) :MachineBase(fname) { /* Constructor. Call base class constructor. Initialise ** derived class data members. */ // VarList has its own constructor } MachineFiveA::~MachineFiveA() { /* Destructor. Tidy up. Automatically call base class ** destructor. ** This method is also virtual. This means that a base ** class pointer pointing to a derived class will call the ** derived class' destructor on any explicit "delete" ** calls. */ // VarList has its own destructor } void MachineFiveA::ProcessDeclaration() { /* Process the declaration by adding the variable to the ** VarList and initialising it. Pretty print the code. ** Spaces and newlines are ignored. ** On entry, b will contain an `i'. ** This method does not update MachineBase::analysis. */ string varname; cout << endl << Spaces(1) << b; machin >> b; // `n' cout << b; machin >> b; // `t' cout << b; varname = ReadUntil('='); vars.Add(varname, 0); cout << varname << b; cout << ReadUntil(';'); cout << b << flush; // b will be `;' on exit vars.PrintList(); } void MachineFiveA::ProcessStatement(int level) { /* Simulate assignments, couts, increments, and while loops. ** When processing the statements within loops, call this ** method recursively. This allows us to follow the structure ** of the code: as shown by our ability to `pretty print' the ** program. Print out a line each time it is `executed'. ** Spaces and newlines are ignored here. `level' is used for ** correct indentation. ** This method does not update MachineBase::analysis. */ string var1, var2; // variable names long addrbegin; // location of beginning of loop if (b == 'w') { // a while loop // process the control portion of the loop first cout << endl << Spaces(level) << "begin \"" << b; cout << ReadUntil('('); cout << b; cout << (var1 = ReadUntil('<')); // set var1 cout << b; cout << (var2 = ReadUntil(')')); // set var2 cout << b; cout << ReadUntil('{'); // don't write out the `{' cout << "\"" << flush; /* the location in the file corresponding to one character ** after the `{' of current block. */ addrbegin = machin.tellg(); // jump to the end of the current loop body JumpEndBlock(); // process the body of the loop while condition == true while (vars.LessThan(var1, var2)) { // jump to beginning of body of loop machin.seekg(addrbegin, ios::beg); machin >> b; // the first char of the statement while (b != '}') { ProcessStatement(level+1); machin >> b; // read first symbol of next statement } } // process the end of the loop cout << endl << Spaces(level); // don't write out the `}' cout << "end \"while\"" << flush; } else if (b == 'c') { // a cout statement // simulate cout by putting the output in a comment cout << endl << Spaces(level) << b; cout << ReadUntil('<'); cout << b; machin >> b; // the second `<' cout << b; var1 = ReadUntil(';'); cout << var1 << b << " \t// \"" << vars.Val(var1) << '"' << flush; } else { // must be inc or assign to zero var1 = b; // first char of variable name machin >> b; while ((b != '+') && (b != '=')) { var1 = var1 + b; machin >> b; } if (b == '+') { // is inc vars.Inc(var1); } else { // assign to 0 vars.Set(var1, 0); } cout << endl << Spaces(level) << var1 << b; cout << ReadUntil(';'); cout << b << flush; vars.PrintList(); } } #endif