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.