lestes::lang::cplus::lex::macro_body Class Reference

#include <macro_body.hh>

Inheritance diagram for lestes::lang::cplus::lex::macro_body:

lestes::std::object lestes::std::mem::keystone List of all members.

Public Types

enum  state_type { BEGIN, PARSED, DEAD }
 type of internal state More...

Public Member Functions

bool parse (const ptr< token_input > &input)
 parses object-like macro body
bool parse (const ptr< token_input > &input, const ptr< macro_head > &head)
 parses function-like macro body
ptr< token_sequenceexpand (const ptr< source_location > &loc)
 expands object-like macro
ptr< token_sequenceexpand (const ptr< source_location > &loc, const ptr< macro_arguments > &mas, const ptr< macro_storage > &macros)
 expands function-like macro
state_type state_get (void) const
 returns internal state
bool equals (const ptr< macro_body > &other) const
 tests equality

Static Public Member Functions

static ptr< macro_bodycreate (void)
 returns empty expansion list

Protected Member Functions

 macro_body (void)
 creates empty expansion list
virtual void gc_mark (void)
 Marks the object.

Private Types

typedef ::lestes::std::vector<
srp< macro_item > > 
items_type
 type of list for storing the expansion items

Private Attributes

state_type state
 internal state of the object
srp< items_typeitems
 the list of expansion items

Detailed Description

Representation of macro expansion list.

Definition at line 61 of file macro_body.hh.


Member Typedef Documentation

typedef ::lestes::std::vector< srp<macro_item> > lestes::lang::cplus::lex::macro_body::items_type [private]

type of list for storing the expansion items

Definition at line 87 of file macro_body.hh.


Member Enumeration Documentation

enum lestes::lang::cplus::lex::macro_body::state_type

type of internal state

Enumerator:
BEGIN 
PARSED 
DEAD 

Definition at line 64 of file macro_body.hh.

00064 { BEGIN, PARSED, DEAD } state_type;


Constructor & Destructor Documentation

lestes::lang::cplus::lex::macro_body::macro_body ( void   )  [protected]

creates empty expansion list

Constructs empty expansion list.

Postcondition:
state == BEGIN

items->size() == 0

Definition at line 59 of file macro_body.cc.

Referenced by create().

00059                           :
00060         state(BEGIN),
00061         items(items_type::create())
00062 {
00063 }


Member Function Documentation

bool lestes::lang::cplus::lex::macro_body::parse ( const ptr< token_input > &  input  ) 

parses object-like macro body

Parses object-like macro replacement list and stores values into self. The input is parsed including the TOK_LINE_END even in case it is ill-formed.

Precondition:
state == BEGIN
Parameters:
input The source for tokens, starting at the beginning of the replacement list.
Returns:
false If the replacement list was ill-formed.

Definition at line 227 of file macro_body.cc.

References BEGIN, lestes::lang::cplus::lex::token_sequence::create(), lestes::lang::cplus::lex::macro_item::create_concat(), lestes::lang::cplus::lex::macro_item::create_literal(), DEAD, lestes::lang::cplus::lex::hash_hash_at_beginning, lestes::lang::cplus::lex::hash_hash_at_end, items, lassert, lassert2, PARSED, lestes::report, state, lestes::lang::cplus::lex::pp_token::TOK_HASH_HASH, and lestes::lang::cplus::lex::pp_token::TOK_LINE_END.

00228 {
00229         lassert(state == BEGIN);
00230         
00231         ptr<token_sequence> literal;
00232         enum { BEGIN, LITERAL, CONCAT, END } fstate = BEGIN;
00233         ptr<pp_token> t;
00234         
00235         do {
00236                 if (fstate == BEGIN)
00237                         t = input->read_front_skip_ws();
00238                 else
00239                         t = input->read_front();
00240 
00241                 if (t->type_get() == pp_token::TOK_HASH_HASH) {
00242                         // check whether the ## is not at the beginning
00243                         if (fstate == BEGIN) {
00244                                 // ## at the beginning of expansion list
00245                                 report << hash_hash_at_beginning << t->location_get();
00246                                 // discard tokens till end of line
00247                                 do {
00248                                         t = input->read_front_skip_ws();
00249                                 } while (t->type_get() != pp_token::TOK_LINE_END);   
00250                                 state = DEAD;
00251                                 return false;
00252                         }
00253                         
00254                         if (fstate == LITERAL) {
00255                                 // flush the literal
00256                                 items->push_back(macro_item::create_literal(literal));
00257                         }
00258 
00259                         literal = token_sequence::create();
00260                         literal->add_back(t);
00261                         
00262                         items->push_back(macro_item::create_concat(literal));
00263                         fstate = CONCAT;
00264                 } else if (t->type_get() == pp_token::TOK_LINE_END) {
00265                         switch (fstate) {
00266                                 case BEGIN:
00267                                         // macro with no content has no macro items
00268                                         break;
00269                                 case CONCAT:
00270                                         // ## at the end of the expansion list
00271                                         report << hash_hash_at_end << t->location_get();
00272                                         state = DEAD;
00273                                         return false;
00274                                 case LITERAL:
00275                                         if (literal->skip_back_ws()) {
00276                                                 // flush the literal
00277                                                 items->push_back(macro_item::create_literal(literal));
00278                                         }
00279                                         break;
00280                                 case END:
00281                                 default:
00282                                         lassert2(false,"You should never get here");
00283                                         break;
00284                         }
00285                         fstate = END;
00286                 } else {
00287                         if (fstate != LITERAL) {
00288                                 // start new literal
00289                                 literal = token_sequence::create();
00290                                 fstate = LITERAL;
00291                         }
00292                         literal->add_back(t);
00293                 }
00294         } while (fstate != END);
00295         state = PARSED;
00296         return true;
00297 }

bool lestes::lang::cplus::lex::macro_body::parse ( const ptr< token_input > &  input,
const ptr< macro_head > &  head 
)

parses function-like macro body

Parses function like macro replacement list and stores values into self.

Precondition:
state == BEGIN
Parameters:
input The source for tokens, starting after parameter list.
Returns:
false If the replacement list was ill-formed.

Definition at line 71 of file macro_body.cc.

References BEGIN, lestes::lang::cplus::lex::token_sequence::create(), lestes::lang::cplus::lex::macro_item::create_concat(), lestes::lang::cplus::lex::macro_item::create_copy(), lestes::lang::cplus::lex::macro_item::create_expansion(), lestes::lang::cplus::lex::macro_item::create_literal(), lestes::lang::cplus::lex::macro_item::create_str(), DEAD, lestes::lang::cplus::lex::macro_item::EXPANSION, lestes::lang::cplus::lex::hash_hash_at_beginning, lestes::lang::cplus::lex::hash_hash_at_end, lestes::lang::cplus::lex::hash_without_parameter, items, lassert, lassert2, PARSED, lestes::report, state, lestes::lang::cplus::lex::pp_token::TOK_BLANK, lestes::lang::cplus::lex::pp_token::TOK_HASH, lestes::lang::cplus::lex::pp_token::TOK_HASH_HASH, and lestes::lang::cplus::lex::pp_token::TOK_LINE_END.

00072 {
00073         lassert(state == BEGIN);
00074         // state of parser
00075         enum {
00076                 BEGIN,
00077                 LITERAL,
00078                 EXPAND,
00079                 NONEXPAND,
00080                 STRINGIFY,
00081                 CONCAT,
00082                 NEWLINE,
00083                 END
00084         } fstate = BEGIN;
00085         ptr<pp_token> t;
00086         ptr<token_sequence> literal;
00087         ulint idx;
00088 
00089         do {
00090                 // TODO pt ::std::cerr << "fstate = " << fstate["blenscXQ"] << '\n';
00091                 if (fstate == BEGIN)
00092                         t = input->read_front_skip_ws();
00093                 else
00094                         t = input->read_front();
00095                 
00096                 if (t->is_name()) {
00097                         idx = head->index_of(t->value_get());
00098                         // if idx is invalid
00099                         if (idx == head->length()) {
00100                                 // ordinary identifier is a part of a literal
00101                                 if (fstate != LITERAL) {
00102                                         literal = token_sequence::create();
00103                                         fstate = LITERAL;
00104                                 }
00105                                 literal->add_back(t);
00106                         } else {
00107                                 if (fstate == CONCAT) {
00108                                         // no expansion after concatenation
00109                                         items->push_back(macro_item::create_copy(idx));
00110                                         fstate = NONEXPAND;
00111                                 } else {
00112                                         if (fstate == LITERAL) {
00113                                                 // flush the literal
00114                                                 items->push_back(macro_item::create_literal(literal));
00115                                         }
00116                                         items->push_back(macro_item::create_expansion(idx));
00117                                         fstate = EXPAND;
00118                                 }
00119                         }
00120                 } else if (t->type_get() == pp_token::TOK_HASH) {
00121                         if (fstate == LITERAL) {
00122                                 // flush the literal
00123                                 items->push_back(macro_item::create_literal(literal));
00124                         }
00125                   
00126                         literal = token_sequence::create();
00127                         // save the hash
00128                         literal->add_back(t);
00129                         t = input->read_front();
00130 
00131                         if (t->type_get() == pp_token::TOK_BLANK) {
00132                                 // add the blank
00133                                 literal->add_back(t);
00134                                 // get the parameter
00135                                 t = input->read_front_skip_ws();
00136                         }
00137 
00138                         if (!t->is_name() ||
00139                                  (idx = head->index_of(t->value_get())) == head->length()) {
00140                                 // # operator without parameter
00141                                 report << hash_without_parameter << t->location_get();
00142                                 // need cleanup till the end of line
00143                                 if (t->type_get() != pp_token::TOK_LINE_END) goto error_cleanup;
00144                                 state = DEAD;
00145                                 return false;
00146                         }
00147                         items->push_back(macro_item::create_str(idx,literal));
00148 
00149                         fstate = STRINGIFY;
00150                 } else if (t->type_get() == pp_token::TOK_HASH_HASH) {
00151                         switch (fstate) {
00152                                 case BEGIN:
00153                                         // ## at the beginning of expansion list
00154                                         report << hash_hash_at_beginning << t->location_get();
00155                                         goto error_cleanup;
00156                                 case LITERAL:
00157                                         // check whether there is EXPAND preceding
00158                                         if (!(items->size() && literal->length() == 1 && literal->peek_front() == pp_token::TOK_BLANK &&
00159                                                  items->back()->action_get() == macro_item::EXPANSION)) break;
00160                                         // fall through
00161                                 case EXPAND:
00162                                         {
00163                                                 // update preceding expansion
00164                                                 ptr<macro_item> mbi = items->back();
00165                                                 items->pop_back();
00166                                                 // update to avoid expansion
00167                                                 items->push_back(macro_item::create_copy(mbi->index_get()));
00168                                         }
00169                                         break;
00170                                 case STRINGIFY:
00171                                 case CONCAT:
00172                                         // okay
00173                                         break;
00174                                 case END:
00175                                 default:
00176                                         lassert2(false,"You should never get here");
00177                                         break;
00178                         }
00179                         if (fstate == LITERAL) {
00180                                 // flush the literal
00181                                 items->push_back(macro_item::create_literal(literal));
00182                         }
00183 
00184                         literal = token_sequence::create();
00185                         literal->add_back(t);
00186 
00187                         items->push_back(macro_item::create_concat(literal));
00188                         fstate = CONCAT;
00189                 } else if (t->type_get() == pp_token::TOK_LINE_END) {
00190                         if (fstate == CONCAT) {
00191                                 // ## at the end of the expansion list
00192                                 report << hash_hash_at_end << t->location_get();
00193                                 state = DEAD;
00194                                 return false;
00195                         }
00196                         if (fstate == LITERAL && literal->skip_back_ws()) {
00197                                 // flush the literal
00198                                 items->push_back(macro_item::create_literal(literal));
00199                         }
00200                         fstate = END;
00201                 } else {
00202                         if (fstate != LITERAL) {
00203                                 literal = token_sequence::create();
00204                                 fstate = LITERAL;
00205                         }
00206                         literal->add_back(t);
00207                 }
00208         } while (fstate != END);
00209         state = PARSED;
00210         return true;
00211 error_cleanup:
00212         // discard tokens till end of line
00213         do {
00214                 t = input->read_front_skip_ws();
00215         } while (t->type_get() != pp_token::TOK_LINE_END);   
00216         state = DEAD;
00217         return false;
00218 }

ptr< token_sequence > lestes::lang::cplus::lex::macro_body::expand ( const ptr< source_location > &  loc  ) 

expands object-like macro

Expand this object-like macro body.

Precondition:
state == PARSED
Parameters:
loc The location of the expansion.
Returns:
The expanded, but not rescanned sequence.

Definition at line 305 of file macro_body.cc.

References lestes::lang::cplus::lex::macro_item::CONCAT, lestes::lang::cplus::lex::token_sequence::create(), lestes::lang::cplus::lex::concat::instance(), items, lassert, lassert2, lestes::lang::cplus::lex::macro_item::LITERAL, PARSED, and state.

00306 {
00307         lassert(state == PARSED);
00308         
00309         ptr<token_sequence> result = token_sequence::create();
00310         ptr<token_sequence> current;
00311         bool concat = false;
00312         items_type::iterator it = items->begin();
00313         items_type::iterator last = items->end();
00314 
00315         for ( ; it != last; ++it) {
00316                 ptr<macro_item> mi = *it;
00317 
00318                 switch (mi->action_get()) {
00319                         case macro_item::CONCAT:
00320                                 if (concat) {
00321                                         // concatenating with ## literal
00322                                         current = mi->value_get();
00323                                 } else {
00324                                         concat = true;
00325                                         // signal first round
00326                                         current = NULL;
00327                                 }
00328                                 break;
00329                         case macro_item::LITERAL:
00330                                 // assign because current is NULL or empty
00331                                 current = mi->value_get();
00332                                 break;
00333                         default:
00334                                 lassert2(false,"You should never get here");
00335                                 break;
00336                 }
00337 
00338                 if (concat) {
00339 
00340                         // if there is token for the right side
00341                         if (current && current->skip_front_ws()) {
00342                                 
00343                                 // TODO pt remove ::std::cerr << "WILL run concat on " << current << ::std::endl;
00344                                 
00345                                 // concat is always after tokens
00346                                 ptr<pp_token> left = result->read_back_skip_ws();
00347                                 // whitespace already cleared
00348                                 ptr<pp_token> right = current->read_front();
00349                                 
00350                                 // errors are handled transparently inside concatenate
00351                                 result->append(concat::instance()->process(left,right));
00352                                 // add the rest of the right part
00353                                 result->append(current);
00354 
00355                                 concat = false;
00356                         }
00357                 } else {
00358                         // no pending concatenation
00359                         result->append(current);
00360                 }
00361         }
00362 
00363         // concatenation shall not be at the end
00364         lassert(concat != true);
00365         // TODO clone(taboo macros, loc)
00366         return result->clone(loc);
00367 }

ptr< token_sequence > lestes::lang::cplus::lex::macro_body::expand ( const ptr< source_location > &  loc,
const ptr< macro_arguments > &  mas,
const ptr< macro_storage > &  macros 
)

expands function-like macro

Expands this function-like macro body.

Todo:
pt Add error message.

pt Add location setting.

Precondition:
state == PARSED
Parameters:
mas The arguments for the macro.
loc The location of the expansion.
Returns:
The expanded, but not rescanned sequence.

NULL in case of error.

Definition at line 379 of file macro_body.cc.

References lestes::lang::cplus::lex::macro_item::CONCAT, lestes::lang::cplus::lex::macro_item::COPY, lestes::lang::cplus::lex::token_sequence::create(), lestes::lang::cplus::lex::macro_item::EXPANSION, lestes::lang::cplus::lex::concat::instance(), items, lassert, lassert2, lestes::lang::cplus::lex::macro_item::LITERAL, PARSED, state, and lestes::lang::cplus::lex::macro_item::STR.

00381 {
00382         lassert(state == PARSED);
00383         
00384         ptr<token_sequence> result = token_sequence::create();
00385         ptr<token_sequence> current;
00386         ptr<pp_token> left;
00387         bool concat = false;
00388         items_type::iterator it = items->begin();
00389         items_type::iterator last = items->end();
00390 
00391         for ( ; it != last; ++it) {
00392                 ptr<macro_item> mi = *it;
00393                 ptr<macro_argument> ma;
00394 
00395                 switch (mi->action_get()) {
00396                         case macro_item::CONCAT:
00397                                 if (concat) {
00398                                         // concatenating with ## literal
00399                                         current = mi->value_get();
00400                                 } else {
00401                                         concat = true;
00402                                         current = NULL;
00403                                 }
00404                                 break;
00405                         case macro_item::LITERAL:
00406                                 current = mi->value_get();
00407                                 break;
00408                         case macro_item::EXPANSION:
00409                                 ma = mas->argument_get(mi->index_get());
00410                                 current = ma->expanded_get(macros);
00411                                 break;
00412                         case macro_item::COPY:
00413                                 ma = mas->argument_get(mi->index_get());
00414                                 current = ma->nonexpanded_get();
00415                                 break;
00416                         case macro_item::STR:
00417                                 ma = mas->argument_get(mi->index_get());
00418                                 current = ma->stringified_get();
00419                                 break;
00420                         default:
00421                                 lassert2(false,"You should never get here");
00422                                 break;
00423                 }
00424 
00425                 if (concat) {
00426                         // if there is token for the right side
00427                         if (current && current->skip_front_ws()) {
00428                                 
00429                                 // TODO pt remove ::std::cerr << "WILL run () concat on " << current << ::std::endl;
00430                                 
00431                                 // check back token
00432                                 ptr<pp_token> left = 
00433                                         result->skip_back_ws() ? result->read_back() : ptr<pp_token>(NULL);
00434                                 ptr<pp_token> right = current->read_front();
00435                                 
00436                                 // errors are handled transparently inside concatenate
00437                                 result->append(concat::instance()->process(left,right));
00438                                 // add the rest of the right part
00439                                 result->append(current);
00440 
00441                                 concat = false;
00442                         }
00443                 } else {
00444                         // no pending concatenation
00445                         result->append(current);
00446                 }
00447                         
00448         }
00449 
00450         if (concat) {
00451                 // check back token
00452                 ptr<pp_token> left = 
00453                         result->skip_back_ws() ? result->read_back() : ptr<pp_token>(NULL);
00454                 // check front token
00455                 ptr<pp_token> right = 
00456                         current->skip_front_ws() ? current->read_front() : ptr<pp_token>(NULL);
00457                 
00458                 // errors are handled transparently inside concatenate
00459                 result->append(concat::instance()->process(left,right));
00460                 // add the rest of the right part
00461                 result->append(current);
00462 
00463                 concat = false;
00464         }
00465         
00466         return result->clone(loc);
00467 }

macro_body::state_type lestes::lang::cplus::lex::macro_body::state_get ( void   )  const

returns internal state

Returns internal state of the object.

Returns:
The internal state of the object.

Definition at line 473 of file macro_body.cc.

References state.

00474 {
00475         return state;
00476 }

bool lestes::lang::cplus::lex::macro_body::equals ( const ptr< macro_body > &  other  )  const

tests equality

Tests equality.

Parameters:
other The macro body to compare with.
Returns:
true If both expansion lists have the same order, spelling and whitespace separation of tokens.

Definition at line 483 of file macro_body.cc.

References lestes::is_equal(), items, PARSED, and state.

00484 {
00485         if (!other || state != other->state_get()) return false;
00486 
00487         if (state != PARSED) return true;
00488 
00489         if (items->size() != other->items->size()) return false;
00490 
00491         items_type::iterator it = items->begin();
00492         items_type::iterator last = items->end();
00493 
00494         items_type::iterator ot = other->items->begin();
00495 
00496         for ( ; it != last; ++it, ++ot) {
00497                 ptr<macro_item> mi = *it;
00498                 ptr<macro_item> oi = *ot;
00499 
00500                 if (!is_equal(mi,oi)) return false;
00501         }
00502                 
00503         return true;
00504 }

ptr< macro_body > lestes::lang::cplus::lex::macro_body::create ( void   )  [static]

returns empty expansion list

Returns empty expansion list.

Postcondition:
state == BEGIN
Returns:
The new empty expansion list.

Definition at line 520 of file macro_body.cc.

References macro_body().

00521 {
00522         return new macro_body();
00523 }

void lestes::lang::cplus::lex::macro_body::gc_mark ( void   )  [protected, virtual]

Marks the object.

Marks the object.

Reimplemented from lestes::std::mem::keystone.

Definition at line 509 of file macro_body.cc.

References lestes::std::mem::keystone::gc_mark(), and items.

00510 {
00511         items.gc_mark();
00512 	::lestes::std::object::gc_mark();
00513 }


Member Data Documentation

state_type lestes::lang::cplus::lex::macro_body::state [private]

internal state of the object

Definition at line 89 of file macro_body.hh.

Referenced by equals(), expand(), parse(), and state_get().

srp<items_type> lestes::lang::cplus::lex::macro_body::items [private]

the list of expansion items

Definition at line 91 of file macro_body.hh.

Referenced by equals(), expand(), gc_mark(), and parse().


The documentation for this class was generated from the following files:
Generated on Mon Feb 12 18:24:17 2007 for lestes by doxygen 1.5.1-20070107