CMSC 435: Assignment 3

Overview

Write a scanner for the C- programming language defined in Appendix A of the textbook. To this end, code a Scanner class and a driver file (CMinus.cc) that repeatedly invokes your scanner’s scanNext method. In the DRIVER, print each token and lexeme in a NEAT tabular format. Code in C++23/26 and use a .cc extension for each implementation file and .hh for each header file. Report any invalid input, along with the line and column numbers (assume both start at one).

So that we all build from the same foundation, use my Token class: Token.hh and Token.cc.

Use this header file Scanner.hh as a basis for your Scanner class, and Scanner.cc as the implementation file. You may modify the private members to suit your needs, but leave the public interface UNCHANGED.

For all remaining assignments, use my .clang-format style file (see the first bullet under Assignments on the course page) to ensure your code meets the formatting requirements. Incorrectly formatted code will NOT be accepted and you will receive a ZERO. You will also want my .clangd file.

Input Specification

Take the name of a C- program as a command-line argument. If no argument is specified read from standard input (this will be tested). Use .cm as the extension for C- source files.

> ./CMinus [ <Program.cm> ]

Output Specification

Output tokens, lexemes, and locations (formatted as (row, column)) as shown in the table below. NO PRINTING should be done in the scanner. Do NOT use a GIANT “switch” or “if” statement to output each token — use a std::array or something similar. Continue scanning after encountering an Error token.

Sample Session

Token           Lexeme           Location
=====           ======           ========
Void            "void"           (1, 1)
Id              "main"           (2, 1)
LParen          "("              (2, 6)
Void            "void"           (2, 7)
RParen          ")"              (2, 11)
...
Error           "&"              (18, 3)
...
EndOfFile       ""               (24, 1)

Required Types, Concepts, and Functions

See header files.

What to Submit

Submit your driver CMinus.cc, your Scanner class (Scanner.cc and Scanner.hh), Token.hh, Token.cc, and a Makefile. ENSURE your Makefile properly buids your program, and that make clean removes all generated files.

Hints

Handle keywords similar to identifiers. When an identifier is recognized, look it up in a data structure. If it’s found, return the corresponding keyword token, otherwise return an identifier token.

You could code your scanner using the DFA approach we discussed in class (and the one your author uses for his TINY getToken function; see Fig 2.10 in the text for the DFA). Alternatively, you could code your scanner in a more ad hoc fashion, which, if done with care, will result in cleaner code. For example, code for member function scanNext could be SIMILAR to

Token
scanNext ()
{
  skipWhitespaceAndComments (); 

  int c = advance ();
  if (std::islpha (c))
    return scanIdentifier (...);
  if (std::isdigit (c))
    return scanNumber (...);
  
  switch (c)
  {
    case '+':
      return Token { ... };

    case '-':
      return Token { ... };
    ...
  }
}

Gary M. Zoppetti, Ph.D.