Listing 1: newexpr.cpp -- translate C++ new expressions into English
//
// Copyright (C) 1996, 1997 by Dan Saks.
// May be copied for private, non-commercial use,
// provided this copyright notice remains intact.
// All other rights reserved.
//
#include <iostream>
#include "scanner.h"
using namespace std;
class parser
{
public:
parser(istream &, ostream &);
private:
enum declarator_category { ABSTRACT, CONCRETE, EITHER, NEW };
enum type_category
{
SIMPLE, SIZED_ARRAY, UNSIZED_ARRAY, FUNCTION, POINTER,
REFERENCE
};
struct recoverable_error { };
scanner input;
ostream &output;
string indent;
void error(const string &);
void must_be(token::category);
string array_suffix(type_category &);
string cv_qualifier_seq();
string declarator
(declarator_category, type_category &, type_category &);
string direct_declarator
(declarator_category, type_category &, type_category &);
string expression_list();
string function_suffix();
string new_expression();
string parameter_declaration();
string parameter_list();
string ptr_operator(type_category &);
string type_specifier_seq();
parser(parser const &);
parser &operator=(parser const &);
};
...
//
// array-suffix =
// "[" [ constant-name | integer-literal ] "]" .
//
string parser::array_suffix(type_category &outer)
{
must_be(token::LEFT_BRACKET);
string as = "array with ";
token::category tc = input.current().kind();
if (tc == token::NAME || tc == token::INT_LITERAL)
{
outer = SIZED_ARRAY;
as += input.current().text() + ' ';
input.get();
}
else
{
outer = UNSIZED_ARRAY;
as += "unspecified number of ";
}
as += "elements of type...\n";
must_be(token::RIGHT_BRACKET);
return indent + as;
}
...
//
// declarator =
// direct-declarator | ptr-operator declarator .
//
string parser::declarator
(declarator_category dc, type_category &inner,
type_category &outer)
{
token::category tc = input.current().kind();
if (tc == token::AMPERSAND || tc == token::STAR
|| tc == token::NAME)
{
type_category ptc;
string p = ptr_operator(ptc);
type_category in, out;
string d = declarator(dc, in, out);
if (ptc == REFERENCE)
{
if (out == SIZED_ARRAY || out == UNSIZED_ARRAY)
error("can't have array of reference");
if (out == POINTER)
error("can't have pointer to reference");
if (out == REFERENCE)
error("can't have reference to reference");
}
if ((inner = in) == SIMPLE)
inner = ptc;
outer = ptc;
return d + p;
}
else
return direct_declarator(dc, inner, outer);
}
//
// direct-declarator =
// [ declarator-id | "(" declarator ")" ]
// { array-suffix | function-suffix } .
//
string parser::direct_declarator
(declarator_category dc, type_category &inner,
type_category &outer)
{
string dd;
token::category tc = input.current().kind();
if (tc == token::IDENTIFIER)
{
if (dc == ABSTRACT || dc == NEW)
error("can't have declarator-id in "
"abstract- or new-declarator");
dd = indent + input.current().text() + " is ...\n";
input.get();
inner = outer = SIMPLE;
}
else if (tc == token::LEFT_PAREN && dc != NEW)
{
bool its_grouping = false;
input.mark();
tc = input.get().kind();
if (tc == token::IDENTIFIER
|| tc == token::AMPERSAND || tc == token::STAR
|| tc == token::LEFT_BRACKET || tc == token::LEFT_PAREN
|| (tc == token::NAME && input.get().kind()
== token::SCOPE))
its_grouping = true;
input.backup();
if (its_grouping)
{
input.get();
dd = declarator(dc, inner, outer);
must_be(token::RIGHT_PAREN);
}
}
if (dd == "")
{
if (dc == CONCRETE)
error("declarator-id missing or obscured"
" by something before it");
dd = indent + "<type> is ...\n";
inner = outer = SIMPLE;
}
for (;;)
{
tc = input.current().kind();
if (tc == token::LEFT_BRACKET)
{
if (outer == FUNCTION)
error("can't have function returning array");
type_category tc;
dd += array_suffix(tc);
if (tc == UNSIZED_ARRAY)
{
if (dc == NEW)
error("can't allocate array"
" with unspecified dimension");
if (outer == SIZED_ARRAY || outer == UNSIZED_ARRAY)
error("only 1st dimension can be unspecified");
}
if (inner == SIMPLE)
inner = tc;
outer = tc;
}
else if (tc == token::LEFT_PAREN && dc != NEW)
{
if (outer == SIZED_ARRAY || outer == UNSIZED_ARRAY)
error("can't have array of function");
if (outer == FUNCTION)
error("can't have function returning function");
dd += function_suffix();
if (inner == SIMPLE)
inner = FUNCTION;
outer = FUNCTION;
}
else
break;
}
return dd;
}
//
// expression-list = expression { "," expression } .
//
string parser::expression_list()
{
token::category tc = input.current().kind();
if (tc != token::INT_LITERAL && tc != token::IDENTIFIER)
error("identifier or literal expected in expression list");
string el = input.current().text();
while (input.get().kind() == token::COMMA)
{
tc = input.get().kind();
if (tc != token::INT_LITERAL && tc != token::IDENTIFIER)
error("identifier or literal expected in expression list");
el += ", " + input.current().text();
}
return el;
}
...
//
// new-expression =
// "new" ( "(" type-specifier-seq new-declarator ")" |
// type-specifier-seq abstract-declarator ) "(" ")" .
//
string parser::new_expression()
{
declarator_category dc;
type_category inner, outer;
string lookup;
if (input.current().kind() == token::SCOPE)
{
input.get();
lookup = "using a global allocation function\n";
}
else
{
lookup = "using an allocation function"
" selected by member lookup\n";
}
must_be(token::NEW);
bool its_placement = false;
string pl;
if (input.current().kind() == token::LEFT_PAREN)
{
input.mark();
token::category tc = input.get().kind();
if (tc == token::INT_LITERAL || tc == token::IDENTIFIER)
its_placement = true;
input.backup();
}
if (its_placement)
{
input.get();
pl = "allocated with placement arguments: "
+ expression_list() + '\n';
must_be(token::RIGHT_PAREN);
}
if (input.current().kind() == token::LEFT_PAREN)
{
dc = ABSTRACT;
input.get();
}
else
dc = NEW;
string d = type_specifier_seq();
string ne = declarator(dc, inner, outer) + d + '\n';
if (inner == FUNCTION)
error("cannot allocate function type");
if (inner == REFERENCE)
error("cannot allocate reference type");
if (inner == UNSIZED_ARRAY)
error("cannot allocate array of unspecified dimension");
if (dc == ABSTRACT)
must_be(token::RIGHT_PAREN);
if (input.current().kind() == token::LEFT_PAREN)
{
input.get();
if (input.current().kind() == token::RIGHT_PAREN)
ne += "with an explicitly empty initializer list\n";
else if (inner == SIZED_ARRAY || inner == UNSIZED_ARRAY)
error("array type cannot have non-empty initializer list");
else
ne += "with initializer list: " + expression_list() + '\n';
must_be(token::RIGHT_PAREN);
}
else
ne += "without an initializer list\n";
return ne + pl + lookup;
}
...
//
// parser =
// { new-expression ";" } .
//
parser::parser(istream &is, ostream &os)
: input(is), output(os)
{
for (;;)
try
{
while (input.get().kind() != token::NO_MORE)
{
string s = new_expression();
if (input.current().kind() != token::SEMICOLON)
error("';' expected");
else
output << s;
}
break;
}
catch (recoverable_error const &)
{
}
}
int main()
{
parser declarations(cin, cout);
return 0;
}
//End of File