Synopsis - Cross-Reference

File: src/Synopsis/Parser.cc
   1//
   2// Copyright (C) 1997 Shigeru Chiba
   3// Copyright (C) 2000 Stefan Seefeld
   4// All rights reserved.
   5// Licensed to the public under the terms of the GNU LGPL (>= 2),
   6// see the file COPYING for details.
   7//
   8#include <Synopsis/PTree.hh>
   9#include <Synopsis/PTree/Display.hh>
  10#include <Synopsis/SymbolLookup.hh>
  11#include <Synopsis/TypeAnalysis.hh>
  12#include "Synopsis/Parser.hh"
  13#include "Synopsis/Lexer.hh"
  14#include <Synopsis/Trace.hh>
  15#include <iostream>
  16
  17using namespace Synopsis;
  18
  19class SyntaxError : public Parser::Error
  20{
  21public:
  22  SyntaxError(const std::string &f, unsigned long l, const std::string &c)
  23    : my_filename(f), my_line(l), my_context(c) {}
  24  virtual void write(std::ostream &) const
  25  {
  26    std::cerr << "Syntax error : " << my_filename << ':' << my_line 
  27	      << ": Error before '" << my_context << '\'' << std::endl;
  28  }
  29private:
  30  std::string   my_filename;
  31  unsigned long my_line;
  32  std::string   my_context;
  33};
  34
  35class UndefinedSymbol : public Parser::Error
  36{
  37public:
  38  UndefinedSymbol(PTree::Encoding const &name,
  39		  std::string const &f, unsigned long l)
  40    : my_name(name), my_filename(f), my_line(l) {}
  41  virtual void write(std::ostream &os) const
  42  {
  43    os << "Undefined symbol : " << my_name.unmangled();
  44    if (!my_filename.empty()) os << " at " << my_filename << ':' << my_line;
  45    os << std::endl;
  46  }
  47private:
  48  PTree::Encoding my_name;
  49  std::string     my_filename;
  50  unsigned long   my_line;
  51};
  52
  53class SymbolAlreadyDefined : public Parser::Error
  54{
  55public:
  56  SymbolAlreadyDefined(PTree::Encoding const &name, 
  57		       std::string const & f1, unsigned long l1,
  58		       std::string const & f2, unsigned long l2)
  59    : my_name(name), my_file1(f1), my_line1(l1), my_file2(f2), my_line2(l2) {}
  60  virtual void write(std::ostream &os) const
  61  {
  62    os << "Symbol already defined : definition of " << my_name.unmangled()
  63       << " at " << my_file1 << ':' << my_line1 << '\n'
  64       << "previously defined at " << my_file2 << ':' << my_line2 << std::endl;
  65  }
  66private:
  67  PTree::Encoding my_name;
  68  std::string     my_file1;
  69  unsigned long   my_line1;
  70  std::string     my_file2;
  71  unsigned long   my_line2;
  72};
  73
  74class SymbolTypeMismatch : public Parser::Error
  75{
  76public:
  77  SymbolTypeMismatch(PTree::Encoding const &name, PTree::Encoding const &type)
  78    : my_name(name), my_type(type) {}
  79  virtual void write(std::ostream &os) const
  80  {
  81    os << "Symbol type mismatch : " << my_name.unmangled()
  82       << " has unexpected type " << my_type.unmangled() << std::endl;
  83  }
  84private:
  85  PTree::Encoding my_name;
  86  PTree::Encoding my_type;
  87};
  88
  89namespace
  90{
  91
  92template <typename T>
  93struct PGuard
  94{
  95  PGuard(Parser &p, T Parser::*m) : parser(p), member(m), saved(p.*m) {}
  96  ~PGuard() { parser.*member = saved;}
  97  Parser &    parser;
  98  T Parser::* member;
  99  T           saved;
 100};
 101
 102const unsigned int max_errors = 10;
 103
 104PTree::Node *wrap_comments(const Lexer::Comments &c)
 105{
 106  PTree::Node *head = 0;
 107  for (Lexer::Comments::const_iterator i = c.begin(); i != c.end(); ++i)
 108    head = PTree::snoc(head, new PTree::Atom(*i));
 109  return head;
 110}
 111
 112PTree::Node *nth_declarator(PTree::Node *decl, size_t n)
 113{
 114  decl = PTree::third(decl);
 115  if(!decl || decl->is_atom()) return 0;
 116
 117  if(PTree::is_a(decl, Token::ntDeclarator))
 118  {	// if it is a function
 119    if(n-- == 0) return decl;
 120  }
 121  else
 122    while(decl && !decl->is_atom())
 123    {
 124      if(n-- == 0) return decl->car();
 125      if((decl = decl->cdr())) decl = decl->cdr(); // skip ,
 126    }
 127  return 0;
 128}
 129
 130void set_declarator_comments(PTree::Declaration *decl, PTree::Node *comments)
 131{
 132  if (!decl) return;
 133
 134  PTree::Node *declarator;
 135  size_t n = 0;
 136  while (true)
 137  {
 138    size_t i = n++;
 139    declarator = nth_declarator(decl, i);
 140    if (!declarator) break;
 141    else if (PTree::is_a(declarator, Token::ntDeclarator))
 142      ((PTree::Declarator*)declarator)->set_comments(comments);
 143  }
 144}
 145
 146//. Helper function to recursively find the first left-most leaf node
 147PTree::Node *leftmost_leaf(PTree::Node *node, PTree::Node *& parent)
 148{
 149  if (!node || node->is_atom()) return node;
 150  // Non-leaf node. So find first leafy child
 151  PTree::Node *leaf;
 152  while (node)
 153  {
 154    if (node->car())
 155    {
 156      // There is a child here..
 157      if (node->car()->is_atom())
 158      {
 159	// And this child is a leaf! return it and set parent
 160	parent = node;
 161	return node->car();
 162      }
 163      if ((leaf = leftmost_leaf(node->car(), parent)))
 164	// Not a leaf so try recursing on it
 165	return leaf;
 166    }
 167    // No leaves from car of this node, so try next cdr
 168    node = node->cdr();
 169  }
 170  return 0;
 171}
 172
 173//. Node is never the leaf. Instead we traverse the left side of the tree
 174//. until we find a leaf, and change the leaf to be a CommentedLeaf.
 175void set_leaf_comments(PTree::Node *node, PTree::Node *comments)
 176{
 177  PTree::Node *parent, *leaf;
 178  PTree::CommentedAtom* cleaf;
 179
 180  // Find leaf
 181  leaf = leftmost_leaf(node, parent);
 182
 183  // Sanity
 184  if (!leaf)
 185  {
 186    std::cerr << "Warning: Failed to find leaf when trying to add comments." << std::endl;
 187    PTree::display(parent, std::cerr, false);
 188    return; 
 189  }
 190
 191  if (!(cleaf = dynamic_cast<PTree::CommentedAtom *>(leaf)))
 192  {
 193    // Must change first child of parent to be a commented leaf
 194    Token tk(leaf->position(), leaf->length(), Token::Comment);
 195    cleaf = new (PTree::GC) PTree::CommentedAtom(tk, comments);
 196    parent->set_car(cleaf);
 197  }
 198  else
 199  {
 200    // Already is a commented leaf, so add the comments to it
 201    comments = PTree::snoc(cleaf->get_comments(), comments);
 202    cleaf->set_comments(comments);
 203  }
 204}
 205
 206}
 207
 208struct Parser::ScopeGuard
 209{
 210  template <typename T>
 211  ScopeGuard(Parser &p, T const *s)
 212    : parser(p), noop(s == 0), scope_was_valid(p.my_scope_is_valid)
 213  {
 214    // If s contains a qualified name this may fail, as the name
 215    // has to be declared before. We record the error but continune
 216    // processing.
 217    try { if (!noop) parser.my_symbols.enter_scope(s);}
 218    catch (SymbolLookup::Undefined const &e)
 219    {
 220      std::string filename;
 221      unsigned long line = 0;
 222      if (e.ptree)
 223	line = parser.my_lexer.origin(e.ptree->begin(), filename);
 224
 225      parser.my_errors.push_back(new UndefinedSymbol(e.name, filename, line));
 226      parser.my_scope_is_valid = false;
 227      noop = true;
 228    }
 229  }
 230  ~ScopeGuard() 
 231  {
 232    if (!noop) parser.my_symbols.leave_scope();
 233    parser.my_scope_is_valid = scope_was_valid;
 234  }
 235  Parser & parser;
 236  bool     noop;
 237  bool     scope_was_valid;
 238};
 239
 240Parser::StatusGuard::StatusGuard(Parser &p)
 241  : my_lexer(p.my_lexer),
 242    my_token_mark(my_lexer.save()),
 243    my_errors(p.my_errors),
 244    my_error_mark(my_errors.size()),
 245    my_committed(false)
 246{
 247}
 248
 249Parser::StatusGuard::~StatusGuard() 
 250{
 251  if (!my_committed)
 252  {
 253    my_lexer.restore(my_token_mark);
 254    my_errors.resize(my_error_mark);
 255  }
 256}
 257
 258Parser::Parser(Lexer &lexer, SymbolFactory &symbols, int ruleset)
 259  : my_lexer(lexer),
 260    my_ruleset(ruleset),
 261    my_symbols(symbols),
 262    my_scope_is_valid(true),
 263    my_comments(0),
 264    my_gt_is_operator(true),
 265    my_in_template_decl(false)
 266{
 267}
 268
 269Parser::~Parser()
 270{
 271}
 272
 273bool Parser::mark_error()
 274{
 275  Trace trace("Parser::mark_error", Trace::PARSING);
 276  Token t1, t2;
 277  my_lexer.look_ahead(0, t1);
 278  my_lexer.look_ahead(1, t2);
 279
 280  std::string filename;
 281  unsigned long line = my_lexer.origin(t1.ptr, filename);
 282
 283  const char *end = t1.ptr;
 284  if(t2.type != '\0') end = t2.ptr + t2.length;
 285  else if(t1.type != '\0') end = t1.ptr + t1.length;
 286  my_errors.push_back(new SyntaxError(filename, line, std::string(t1.ptr, end - t1.ptr)));
 287  return my_errors.size() < max_errors;
 288}
 289
 290template <typename T>
 291bool Parser::declare(T *t)
 292{
 293  // If the scope isn't valid, do nothing.
 294  if (!my_scope_is_valid) return true;
 295  try
 296  {
 297    my_symbols.declare(t);
 298  }
 299  catch (SymbolLookup::Undefined const &e)
 300  {
 301    std::string filename;
 302    unsigned long line = 0;
 303    if (e.ptree)
 304      line = my_lexer.origin(e.ptree->begin(), filename);
 305
 306    my_errors.push_back(new UndefinedSymbol(e.name, filename, line));
 307  }
 308  catch (SymbolLookup::MultiplyDefined const &e)
 309  {
 310    std::string file1;
 311    unsigned long line1 = my_lexer.origin(e.declaration->begin(), file1);
 312    std::string file2;
 313    unsigned long line2 = my_lexer.origin(e.original->begin(), file2);
 314    my_errors.push_back(new SymbolAlreadyDefined(e.name,
 315						 file1, line1,
 316						 file2, line2));
 317  }
 318  catch (SymbolLookup::TypeError const &e)
 319  {
 320    my_errors.push_back(new SymbolTypeMismatch(e.name, e.type));
 321  }
 322  return my_errors.size() < max_errors;
 323}
 324
 325unsigned long Parser::origin(const char *ptr,
 326			     std::string &filename) const
 327{
 328  return my_lexer.origin(ptr, filename);
 329}
 330
 331void Parser::show_message_head(const char *pos)
 332{
 333  std::string filename;
 334  unsigned long line = origin(pos, filename);
 335  std::cerr << filename << ':' << line << ": ";
 336}
 337
 338PTree::Node *Parser::parse()
 339{
 340  Trace trace("Parser::parse", Trace::PARSING);
 341  PTree::Node *statements = 0;
 342  while(my_lexer.look_ahead(0) != '\0')
 343  {
 344    PTree::Node *def;
 345    if(definition(def))
 346    {
 347      statements = PTree::nconc(statements, PTree::list(def));
 348    }
 349    else
 350    {
 351      if(!mark_error()) return 0; // too many errors
 352      skip_to(';');
 353      Token tk;
 354      my_lexer.get_token(tk);	// ignore ';'
 355    }
 356  }
 357  // Retrieve trailing comments
 358  PTree::Node *c = wrap_comments(my_lexer.get_comments());
 359  if (c)
 360  {
 361    // Use zero-length CommentedAtom as special marker.
 362    // Should we define a 'PTree::Comment' atom for those comments that
 363    // don't clash with the grammar ? At least that seems less hackish than this:
 364    c = new PTree::CommentedAtom(c->begin(), 0, c);
 365    statements = PTree::nconc(statements, PTree::list(c));
 366  }
 367  return statements;
 368}
 369
 370/*
 371  definition
 372  : null.declaration
 373  | typedef
 374  | template.decl
 375  | metaclass.decl
 376  | linkage.spec
 377  | namespace.spec
 378  | namespace.alias
 379  | using.declaration
 380  | extern.template.decl
 381  | declaration
 382*/
 383bool Parser::definition(PTree::Node *&p)
 384{
 385  Trace trace("Parser::definition", Trace::PARSING);
 386  bool res;
 387  int t = my_lexer.look_ahead(0);
 388  if(t == ';')
 389    res = null_declaration(p);
 390  else if(t == Token::TYPEDEF)
 391  {
 392    PTree::Typedef *td;
 393    res = typedef_(td);
 394    p = td;
 395  }
 396  else if(t == Token::TEMPLATE)
 397    res = template_decl(p);
 398  else if(t == Token::METACLASS)
 399    res = metaclass_decl(p);
 400  else if(t == Token::EXTERN && my_lexer.look_ahead(1) == Token::StringL)
 401    res = linkage_spec(p);
 402  else if(t == Token::EXTERN && my_lexer.look_ahead(1) == Token::TEMPLATE &&
 403	  my_ruleset & GCC)
 404    res = extern_template_decl(p);
 405  else if(t == Token::NAMESPACE && my_lexer.look_ahead(2) == '=')
 406  {
 407    PTree::NamespaceAlias *alias;
 408    res = namespace_alias(alias);
 409    p = alias;
 410  }
 411  else if(t == Token::NAMESPACE)
 412  {
 413    PTree::NamespaceSpec *spec;
 414    res = namespace_spec(spec);
 415    p = spec;
 416  }
 417  else if(t == Token::USING)
 418  {
 419    if (my_lexer.look_ahead(1) == Token::NAMESPACE)
 420    {
 421      PTree::UsingDirective *udir;
 422      res = using_directive(udir);
 423      if (res)
 424      {
 425	declare(udir);
 426	p = udir;
 427      }
 428    }
 429    else
 430    {
 431      PTree::UsingDeclaration *udecl;
 432      res = using_declaration(udecl);
 433      if (res)
 434      {
 435	declare(udecl);
 436	p = udecl;
 437      }
 438    }
 439  }
 440  else 
 441  {
 442    PTree::Declaration *decl;
 443    if (!declaration(decl)) return false;
 444    PTree::Node *c = wrap_comments(my_lexer.get_comments());
 445    if (c) set_declarator_comments(decl, c);
 446    p = decl;
 447    declare(decl);
 448    return true;
 449  }
 450  my_lexer.get_comments();
 451  return res;
 452}
 453
 454bool Parser::null_declaration(PTree::Node *&decl)
 455{
 456  Trace trace("Parser::null_declaration", Trace::PARSING);
 457  Token tk;
 458
 459  if(my_lexer.get_token(tk) != ';') return false;
 460  decl = new PTree::Declaration(0, PTree::list(0, new PTree::Atom(tk)));
 461  return true;
 462}
 463
 464/*
 465  typedef
 466  : TYPEDEF type.specifier init_declarator_list ';'
 467*/
 468bool Parser::typedef_(PTree::Typedef *&def)
 469{
 470  Trace trace("Parser::typedef_", Trace::PARSING);
 471  Token tk;
 472  PTree::Node *type_name, *decl;
 473  PTree::Encoding type_encode;
 474
 475  if(my_lexer.get_token(tk) != Token::TYPEDEF) return false;
 476
 477  def = new PTree::Typedef(new PTree::Kwd::Typedef(tk));
 478  if(!type_specifier(type_name, false, type_encode)) return false;
 479
 480  def = PTree::snoc(def, type_name);
 481  if(!init_declarator_list(decl, type_encode, true)) return false;
 482  if(my_lexer.get_token(tk) != ';') return false;
 483
 484  def = PTree::nconc(def, PTree::list(decl, new PTree::Atom(tk)));
 485  declare(def);
 486  return true;
 487}
 488
 489/*
 490  type.specifier
 491  : {cv.qualify} (integral.or.class.spec | name) {cv.qualify}
 492*/
 493bool Parser::type_specifier(PTree::Node *&tspec, bool check, PTree::Encoding &encode)
 494{
 495  Trace trace("Parser::type_specifier", Trace::PARSING);
 496  PTree::Node *cv_q, *cv_q2;
 497
 498  // FIXME: Need to rewrite this to correctly reflect the grammar, in particular
 499  //        'typename' ...
 500  //        Do we need a new node type ('Typename') ?
 501  if(!opt_cv_qualifier(cv_q) || !opt_integral_type_or_class_spec(tspec, encode))
 502    return false;
 503  
 504  if(!tspec)
 505  {
 506    if(check)
 507    {
 508      Token tk;
 509      my_lexer.look_ahead(0, tk);
 510      if(!maybe_typename_or_class_template(tk))
 511	return false;
 512    }
 513
 514    if(!name(tspec, encode))
 515      return false;
 516  }
 517
 518  if(!opt_cv_qualifier(cv_q2))
 519    return false;
 520
 521  if(cv_q)
 522  {
 523    tspec = PTree::snoc(cv_q, tspec);
 524    if(cv_q2)
 525      tspec = PTree::nconc(tspec, cv_q2);
 526  }
 527  else if(cv_q2)
 528    tspec = PTree::cons(tspec, cv_q2);
 529
 530  encode.cv_qualify(cv_q, cv_q2);
 531  return true;
 532}
 533
 534// is_type_specifier() returns true if the next is probably a type specifier.
 535bool Parser::is_type_specifier()
 536{
 537  int t = my_lexer.look_ahead(0);
 538  if(t == Token::TYPENAME || t == Token::Identifier || t == Token::Scope
 539     || t == Token::CONST || t == Token::VOLATILE
 540     || t == Token::CHAR || t == Token::WCHAR 
 541     || t == Token::INT || t == Token::SHORT || t == Token::LONG
 542     || t == Token::SIGNED || t == Token::UNSIGNED || t == Token::FLOAT || t == Token::DOUBLE
 543     || t == Token::VOID || t == Token::BOOLEAN
 544     || t == Token::CLASS || t == Token::STRUCT || t == Token::UNION || t == Token::ENUM)
 545    return true;
 546  else if (my_ruleset & MSVC && t == Token::INT64)
 547    return true;
 548  else
 549    return false;
 550}
 551
 552/*
 553  metaclass.decl
 554  : METACLASS Identifier {{':'} Identifier {'(' meta.arguments ')'}} ';'
 555
 556  We allow two kinds of syntax:
 557
 558  metaclass <metaclass> <class>(...);
 559  metaclass <metaclass>;
 560  metaclass <class> : <metaclass>(...);		// for backward compatibility
 561*/
 562bool Parser::metaclass_decl(PTree::Node *&decl)
 563{
 564  int t;
 565  Token tk1, tk2, tk3, tk4;
 566  PTree::Node *metaclass_name;
 567
 568  if(my_lexer.get_token(tk1) != Token::METACLASS)
 569    return false;
 570
 571  if(my_lexer.get_token(tk2) != Token::Identifier)
 572    return false;
 573
 574  t = my_lexer.get_token(tk3);
 575  if(t == Token::Identifier)
 576  {
 577    metaclass_name = new PTree::Identifier(tk2);
 578    decl = new PTree::MetaclassDecl(new PTree::UserKeyword(tk1),
 579				    PTree::list(metaclass_name,
 580						new PTree::Identifier(tk3)));
 581  }
 582  else if(t == ':')
 583  {
 584    if(my_lexer.get_token(tk4) != Token::Identifier)
 585      return false;
 586
 587    metaclass_name = new PTree::Identifier(tk4);
 588    decl = new PTree::MetaclassDecl(new PTree::UserKeyword(tk1),
 589				    PTree::list(metaclass_name,
 590						new PTree::Identifier(tk2)));
 591  }
 592  else if(t == ';')
 593  {
 594    metaclass_name = new PTree::Identifier(tk2);
 595    decl = new PTree::MetaclassDecl(new PTree::UserKeyword(tk1),
 596				    PTree::list(metaclass_name, 0,
 597						new PTree::Atom(tk3)));
 598    return true;
 599  }
 600  else
 601    return false;
 602
 603  t = my_lexer.get_token(tk1);
 604  if(t == '(')
 605  {
 606    PTree::Node *args;
 607    if(!meta_arguments(args))
 608      return false;
 609
 610    if(my_lexer.get_token(tk2) != ')')
 611      return false;
 612
 613    decl = PTree::nconc(decl, PTree::list(new PTree::Atom(tk1), args,
 614					  new PTree::Atom(tk2)));
 615    t = my_lexer.get_token(tk1);
 616  }
 617
 618  if(t == ';')
 619  {
 620    decl = PTree::snoc(decl, new PTree::Atom(tk1));
 621    return true;
 622  }
 623  else
 624    return false;
 625}
 626
 627/*
 628  meta.arguments : (anything but ')')*
 629*/
 630bool Parser::meta_arguments(PTree::Node *&args)
 631{
 632  int t;
 633  Token tk;
 634
 635  int n = 1;
 636  args = 0;
 637  while(true)
 638  {
 639    t = my_lexer.look_ahead(0);
 640    if(t == '\0')
 641      return false;
 642    else if(t == '(')
 643      ++n;
 644    else if(t == ')')
 645      if(--n <= 0)
 646	return true;
 647
 648    my_lexer.get_token(tk);
 649    args = PTree::snoc(args, new PTree::Atom(tk));
 650  }
 651}
 652
 653/*
 654  linkage.spec
 655  : EXTERN StringL definition
 656  |  EXTERN StringL linkage.body
 657*/
 658bool Parser::linkage_spec(PTree::Node *&spec)
 659{
 660  Trace trace("Parser::linkage_spec", Trace::PARSING);
 661  Token tk1, tk2;
 662  PTree::Node *body;
 663
 664  if(my_lexer.get_token(tk1) != Token::EXTERN) return false;
 665  if(my_lexer.get_token(tk2) != Token::StringL) return false;
 666
 667  spec = new PTree::LinkageSpec(new PTree::Kwd::Extern(tk1),
 668				PTree::list(new PTree::Atom(tk2)));
 669  if(my_lexer.look_ahead(0) == '{')
 670  {
 671    if(!linkage_body(body)) return false;
 672  }
 673  else
 674    if(!definition(body)) return false;
 675
 676  spec = PTree::snoc(spec, body);
 677  return true;
 678}
 679
 680/*
 681  namespace.spec
 682  : NAMESPACE Identifier definition
 683  | NAMESPACE { Identifier } linkage.body
 684*/
 685bool Parser::namespace_spec(PTree::NamespaceSpec *&spec)
 686{
 687  Trace trace("Parser::namespace_spec", Trace::PARSING);
 688
 689  Token tk;
 690  if(my_lexer.get_token(tk) != Token::NAMESPACE) return false;
 691  PTree::Kwd::Namespace *namespace_ = new PTree::Kwd::Namespace(tk);
 692
 693  PTree::Node *comments = wrap_comments(my_lexer.get_comments());
 694
 695  PTree::Node *name;
 696  if(my_lexer.look_ahead(0) == '{') name = 0;
 697  else
 698    if(my_lexer.get_token(tk) == Token::Identifier)
 699      name = new PTree::Identifier(tk);
 700    else return false;
 701
 702  spec = new PTree::NamespaceSpec(namespace_, PTree::list(name, 0));
 703  spec->set_comments(comments);
 704
 705  PTree::Node *body;
 706  if(my_lexer.look_ahead(0) == '{')
 707  {
 708    declare(spec);
 709    ScopeGuard guard(*this, spec);
 710    if(!linkage_body(body)) return false;
 711  }
 712  else if(!definition(body)) return false;
 713
 714  PTree::tail(spec, 2)->set_car(body);
 715
 716  return true;
 717}
 718
 719/*
 720  namespace.alias : NAMESPACE Identifier '=' Identifier ';'
 721*/
 722bool Parser::namespace_alias(PTree::NamespaceAlias *&exp)
 723{
 724  Trace trace("Parser::namespace_alias", Trace::PARSING);
 725  Token tk;
 726
 727  if(my_lexer.get_token(tk) != Token::NAMESPACE) return false;
 728  PTree::Node *ns = new PTree::Kwd::Namespace(tk);
 729
 730  if (my_lexer.get_token(tk) != Token::Identifier) return false;
 731  PTree::Node *alias = new PTree::Identifier(tk);
 732
 733  if (my_lexer.get_token(tk) != '=') return false;
 734  PTree::Node *eq = new PTree::Atom(tk);
 735
 736  PTree::Node *name;
 737  PTree::Encoding encode;
 738  int length = 0;
 739  if(my_lexer.look_ahead(0) == Token::Scope)
 740  {
 741    my_lexer.get_token(tk);
 742    name = PTree::list(new PTree::Atom(tk));
 743    encode.global_scope();
 744    ++length;
 745  }
 746  else name = 0;
 747
 748  while (true)
 749  {
 750    if (my_lexer.get_token(tk) != Token::Identifier) return false;
 751    PTree::Node *n = new PTree::Identifier(tk);
 752    encode.simple_name(n);
 753    ++length;
 754    
 755    if(my_lexer.look_ahead(0) == Token::Scope)
 756    {
 757      my_lexer.get_token(tk);
 758      name = PTree::nconc(name, PTree::list(n, new PTree::Atom(tk)));
 759    }
 760    else
 761    {
 762      if(name == 0) name = n;
 763      else name = PTree::snoc(name, n);
 764
 765      if(length > 1) encode.qualified(length);
 766
 767      break;
 768    }
 769  }
 770
 771  if (my_lexer.get_token(tk) != ';') return false;
 772
 773  exp = new PTree::NamespaceAlias(ns, PTree::list(alias, eq, 
 774						  name, new PTree::Atom(tk)));
 775  return true;
 776}
 777
 778/*
 779  using.directive
 780  : USING NAMESPACE name
 781*/
 782bool Parser::using_directive(PTree::UsingDirecti