Logo Search packages:      
Sourcecode: pccts version File versions  Download package

gen.c

/* Code generator for SORCERER
 *
 * Translate sorcerer rules (in intermediate trees) to C / C++
 *
 * SOFTWARE RIGHTS
 *
 * We reserve no LEGAL rights to SORCERER -- SORCERER is in the public
 * domain.  An individual or company may do whatever they wish with
 * source code distributed with SORCERER or the code generated by
 * SORCERER, including the incorporation of SORCERER, or its output, into
 * commerical software.
 *
 * We encourage users to develop software with SORCERER.  However, we do
 * ask that credit is given to us for developing SORCERER.  By "credit",
 * we mean that if you incorporate our source code into one of your
 * programs (commercial product, research project, or otherwise) that you
 * acknowledge this fact somewhere in the documentation, research report,
 * etc...  If you like SORCERER and have developed a nice tool with the
 * output, please mention that you developed it using SORCERER.  In
 * addition, we ask that this header remain intact in our source code.
 * As long as these guidelines are kept, we expect to continue enhancing
 * this system and expect to make other tools available as they are
 * completed.
 *
 * SORCERER 1.00B
 * Terence Parr
 * AHPCRC, University of Minnesota
 * 1992-2001
 *
 * The latest (October 1994) transformation mode works as follows:
 *
 *          o     All elements set _tresult, a function-scoped var
 *          o     All rules are passed the address of a SORAST ptr
 *                called '_result' that is set at the end of each
 *                alternative.  The return tree is guaranteed to
 *                be complete only at this point.
 *          o     Each alt AND #(...) tree have their own root (_r),
 *                sibling (_s) and tail/end pointers (_e).  #(...)  trees
 *                set _tresult just before exiting their scope.  Hence,
 *                #(...) are just like elements--they set _tresult.
 *          o     At the end of a rule, *_result is set to _tresult.
 *          o     After each root node ref, a _mkroot(&_r,&_s,&_e,_tresult)
 *                is generated to set the pointers.
 *          o     After each child node ref, a _mkchild(&_r,&_s,&_e,_tresult)
 *                is generated to set the pointers.
 *          o     After each rule ref, a _mkroot(&_r,&_s,&_e,_tresult)
 *                is generated to set the pointers.
 *          o     After each #(...) ref, a _mkroot(&_r,&_s,&_e,_tresult)
 *                is generated to set the pointers.
 *          o     token references: gen a _tresult=ast_dup(_t);
 *                (only if labeled, however).
 *          o     rules or alts with nocopy set don't construct trees.
 */
#include "pcctscfg.h"
#include "stdpccts.h"
#include "sym.h"
#include "proto.h"

static outfile = -1;
static char *current_rule;
static ListNode *labels_for_func = NULL;
static AST *whichRule;
static int tabs=0;
#define TAB {int i=1; for (;i<=tabs;i++) {putc('\t', output);}}

#define PastWhiteSpace(s)     while (*(s) == ' ' || *(s) == '\t') {s++;}


static void
#ifdef __USE_PROTOS
go_down(int nl)
#else
go_down(nl)
int nl;
#endif
{
      fprintf(output, "_DOWN;");
      if ( nl ) fprintf(output, "\n");
}

static void
#ifdef __USE_PROTOS
go_right(int nl)
#else
go_right(nl)
int nl;
#endif
{
      fprintf(output, "_RIGHT;");
      if ( nl ) fprintf(output, "\n");
}

void
#ifdef __USE_PROTOS
gen_info_hdr( FILE *f )
#else
gen_info_hdr( f )
FILE *f;
#endif
{
      fprintf(f, "/*\n");
      fprintf(f, " * S O R C E R E R  T r a n s l a t i o n  H e a d e r\n");
      fprintf(f, " *\n");
      fprintf(f, " * SORCERER Developed by Terence Parr, Aaron Sawdey, & Gary Funck\n");
      fprintf(f, " * Parr Research Corporation, Intrepid Technology, University of Minnesota\n");
      fprintf(f, " * 1992-1994\n");
      fprintf(f, " * SORCERER Version %s\n", VersionText);
      fprintf(f, " */\n");
}

void
#ifdef __USE_PROTOS
gen_hdr_CPP( void )
#else
gen_hdr_CPP( )
#endif
{
      char CPPParser_h_Name[MaxFileName+1];

      gen_info_hdr(output);
      fprintf(output, "#define SORCERER_VERSION\t%s\n", VersionNumber);
      if ( transform ) fprintf(output, "#define SORCERER_TRANSFORM\n");
      else fprintf(output, "#define SORCERER_NONTRANSFORM\n");
/*    Don't gen header action here as it's in the ClassName.h
      if ( header_action!=NULL )
            dumpAction(header_action, output, 0, -1, 0, 1); */
      fprintf(output, "#include \"%s\"\n", STPARSER_H);

      if ( UserDefdTokens ) fprintf(output, "#include \"%s\"\n", tokdefs_file);
      strcpy(CPPParser_h_Name, CurClassName);
      strcat(CPPParser_h_Name, ".h");
      fprintf(output, "#include \"%s\"\n", CPPParser_h_Name);
}

void
#ifdef __USE_PROTOS
gen_hdr_C( void )
#else
gen_hdr_C( )
#endif
{
      if ( Inline ) return;
      gen_info_hdr(output);
      fprintf(output, "#define SORCERER_VERSION\t%s\n", VersionNumber);
      if ( transform ) fprintf(output, "#define SORCERER_TRANSFORM\n");
      else fprintf(output, "#define SORCERER_NONTRANSFORM\n");
      fprintf(output, "#include \"pcctscfg.h\"\n");
      fprintf(output, "#include <stdio.h>\n");
      fprintf(output, "#include <setjmp.h>\n");
      if ( Prefix[0]!='\0' )
      {
            fprintf(output, "/* rename error routines; used in macros, must use /lib/cpp */\n");
            fprintf(output, "#define mismatched_token %smismatched_token\n", Prefix);
            fprintf(output, "#define mismatched_range %smismatched_range\n", Prefix);
            fprintf(output, "#define missing_wildcard %smissing_wildcard\n", Prefix);
            fprintf(output, "#define no_viable_alt %sno_viable_alt\n", Prefix);
            fprintf(output, "#define sorcerer_panic %ssorcerer_panic\n", Prefix);
      }
      if ( header_action!=NULL )
            dumpAction(header_action, output, 0, -1, 0, 1);

      /* make a #define for the STreeParser containing the ref vars */
      if ( AllRefVars!=NULL )
      {
            ListNode *p;
            fprintf(output, "#define _REFVARS \\\n");
            for (p = AllRefVars->next; p!=NULL; p=p->next)
            {
                  RefVarRec *r = (RefVarRec *)p->elem;
                  fprintf(output, "\t%s; \\\n", r->decl);
            }
            fprintf(output, "\n\n");
      }

      fprintf(output, "#include \"sorcerer.h\"\n");
      if ( UserDefdTokens ) fprintf(output, "#include \"%s\"\n", tokdefs_file);
      if ( GenProtoFile!=NULL ) fprintf(output, "#include \"%s\"\n", GenProtoFile);
      else GenRulePrototypes( output, 0 );
      if ( transform ) fprintf(output, "#include \"sorcerer.c\"\n");
}

void
#ifdef __USE_PROTOS
gen_hdr( void )
#else
gen_hdr( )
#endif
{
      if ( GenCPP ) gen_hdr_CPP();
      else gen_hdr_C();
}

void
#ifdef __USE_PROTOS
gen_hdr1( void )
#else
gen_hdr1( )
#endif
{
      if ( !Inline )
      {
            gen_hdr();
      }

      if ( GenCPP )
      {
/*          fprintf(output, "#include \"%s\"\n", STREESUPPORT_C); */
      }
      else {
            /* make a func to init the ref vars with inits */
            fprintf(output, "\nvoid\n");
            fprintf(output, "#ifdef __USE_PROTOS\n");
            fprintf(output, "_refvar_inits(STreeParser *p)\n");
            fprintf(output, "#else\n");
            fprintf(output, "_refvar_inits(p)\n");
            fprintf(output, "STreeParser *p;\n");
            fprintf(output, "#endif\n");
            fprintf(output, "{\n");
            if ( AllRefVars!=NULL )
            {
                  ListNode *p;
                  for (p = AllRefVars->next; p!=NULL; p=p->next)
                  {
                        RefVarRec *r = (RefVarRec *)p->elem;
                        if ( r->init[0]!='\0' )
                              fprintf(output, "\tp->%s=%s;\n", r->var, r->init);
                  }
            }
            fprintf(output, "}\n\n");
      }

      if ( before_actions != NULL )
      {
            ListNode *p;
            for (p = before_actions->next; p!=NULL; p=p->next)
          dumpAction( (char *)p->elem, output, 0, -1, 0, 1);
      }
}

void
#ifdef __USE_PROTOS
gen( AST *t )
#else
gen( t )
AST *t;
#endif
{
      if ( t==NULL ) return;
      while ( t!=NULL && t->token == NonTerm )
      {
            if ( labels_for_func != NULL )
            {
                  /* reset 'defined' flag for previously defined labels and free list */
                  ListNode *p, *q;
                  for (p = labels_for_func->next; p!=NULL; p=q)
                  {
                        SymEntry *s = (SymEntry *)p->elem;
                        s->defined = 0;
                        q = p->next;
                        free(p);
                  }
                  free(labels_for_func);
                  labels_for_func = NULL;
            }
            gen_rule(t);
            t = t->right;
      }

      if ( after_actions != NULL )
      {
            ListNode *p;
            for (p = after_actions->next; p!=NULL; p=p->next)
                  dumpAction( (char *)p->elem, output, 0, -1, 0, 1);
      }
      fclose(output);
}

void
#ifdef __USE_PROTOS
gen_rule( AST *t )
#else
gen_rule( t )
AST *t;
#endif
{
      SymEntry *s;

      if ( t==NULL ) return;
      whichRule=t;
      s = (SymEntry *) hash_get(symbols, t->text);
      require(s!=NULL, "gen_rule: sym tab broken");
      
      if ( t->file != outfile )      /* open new output file if need to */
      {
            if (strcmp(FileStr[t->file], "stdin")==0) output = stdout;
            else {
                  if ( output != NULL ) fclose( output );
                  output = fopen(OutMetaName(outname(FileStr[t->file])), "w");
                  require(output != NULL, "gen_rule: can't open output file");
#ifdef SPECIAL_FOPEN
                  special_fopen_actions(OutMetaName(outname(FileStr[t->file])));
#endif
            }
            if ( outfile == -1 ) gen_hdr1();
            else gen_hdr();
            outfile = t->file;
      }

      fprintf(output, "\n");
      current_rule = t->text;
      GenRulePrototype(output, t, s, 0);

      /* What locals do we need? */
      tabs=1;
      if ( GenCPP ) fprintf(output, "{\n\tSORASTBase *_t = *_root;\n");
      else fprintf(output, "{\n\tSORAST *_t = *_root;\n");
      if ( s->rt!=NULL ) fprintf(output, "\t%s;\n", s->rt);
      if ( transform )
      {
            if ( GenCPP ) fprintf(output, "\tSORASTBase *_tresult=NULL;\n");
            else fprintf(output, "\tSORAST *_tresult=NULL;\n");
            fprintf(output, "\tTREE_CONSTR_PTRS;\n");
      }

      if ( t->refvars!=NULL )
      {
            ListNode *p;
            for (p = t->refvars->next; p!=NULL; p=p->next)
            {
                  RefVarRec *r = (RefVarRec *)p->elem;
                  if ( !r->global ) {
                        TAB;
                        dump_prefixed_decl("_save_", r->decl, output);
                        if ( GenCPP ) fprintf(output, "=%s;\n", r->var);
                        else fprintf(output, "=_parser->%s;\n", r->var);
                  }
            }
      }

      define_labels_in_block(t->down);
      if ( found_guess_block ) fprintf(output, "\t_GUESS_BLOCK;\n");
      if ( transform ) fprintf(output, "  *_result = NULL;\n");
      gen_block(t->down, BLOCK);
      TAB;
      fprintf(output, "*_root = _t;\n");

      /* reset any ref vars defined in this routine */
      if ( t->refvars!=NULL )
      {
            ListNode *p;
            for (p = t->refvars->next; p!=NULL; p=p->next)
            {
                  RefVarRec *r = (RefVarRec *)p->elem;
                  if ( !r->global )
                  {
                        if ( GenCPP ) fprintf(output, "\t%s = _save_%s;\n", r->var, r->var);
                        else fprintf(output, "\t_parser->%s = _save_%s;\n", r->var, r->var);
                  }
            }
      }

      /* set result of tree copying efforts if no ! on rule */
      if ( transform&&!t->no_copy ) {
            TAB;
            /* The 'if' check in front of the *_result assignment ensures
             * that if someone sets the result before here, don't mess with
             * it.  This assignment is the default.
             */
            fprintf(output, "if ( (*_result) == NULL ) *_result = _r;\n");
      }

      /* send back and return value */
      if ( s->rt!=NULL )
      {
            char *str = s->rt;
            TAB;
            fprintf(output, "return ");
            DumpNextNameInDef(&str, output);
            fprintf(output, ";\n");
      }

      tabs=0;
      fprintf(output, "}\n");
}

/*
 * The lookahead is stored in the 1st node of each alt of the block.
 * The Lookahead of what follows (for CLOSURE and OPT) blocks, is stored
 * in the node which branches over the enclosed, optional block.
 */
void
#ifdef __USE_PROTOS
gen_block( AST *q, int block_type )
#else
gen_block( q, block_type )
AST *q;
int block_type;
#endif
{
  AST *t = q, *u, *g;
      GLA *start_state, *follow=NULL;
      int need_right_curly=0, guess_block_in_prev_alt=0, num_alts=0;
      require(q!=NULL, "gen_block: NULL block");
      require(q->start_state!=NULL, "gen_block: NULL start state");

      start_state = t->start_state->p1;
      require(start_state!=NULL, "gen_block: no GLA start state for AST block");

      switch ( block_type ) {
      case PRED_OP :
            TAB;
            fprintf(output, "{_SAVE; TREE_CONSTR_PTRS;\n");
            break;
      case CLOSURE :
            TAB;
            fprintf(output, "{int _done=0;\n");
            TAB;
            fprintf(output, "while ( !_done ) {\n");
            tabs++;
            break;
      case POS_CLOSURE :
            TAB;
            fprintf(output, "{int _done=0;\n");
            TAB;
            fprintf(output, "do {\n");
            tabs++;
      }

      /* Error if (...)? with only one alt */
      for (u = q->down; u!=NULL; u=u->right ) {num_alts++;}
      g = first_guess_block(q->down);
      if ( num_alts==1 && g!=NULL )
      {
            warnFL("(...)? predicate in block with one alternative; will generate bad code",
                     FileStr[g->file], g->line);
      }

      t = t->down;      /* move down to first alt */
      while ( t!=NULL && t->token == ALT )
      {
            require(start_state!=NULL, "gen_block: invalid GLA for block");
            if ( t!=q->down ) {
                  TAB;
                  fprintf(output, "else {\n");
                  need_right_curly++;
            }
            code_for_guess_block(t, &guess_block_in_prev_alt);
            TAB;
            fprintf(output, "if (");
            /* To prevent/detect infinite recursion, ensure 'visited' flag is set
             * on node starting this alt
             */
            start_state->visited = 1;
            start_state->lookahead = gen_prediction_expr(t, start_state->p1);
            start_state->visited = 0;
            fprintf(output, " ) {\n");
            tabs++;
            gen_alt(t);
            tabs--; TAB;
            fprintf(output, "}\n");
            t = t->right;                             /* move to next alt in AST */
            start_state = start_state->p2;      /* move to next alt in GLA */
      }

      switch ( block_type ) {
      case OPT :
      case CLOSURE :
            follow = q->start_state->p2;
            break;
      case POS_CLOSURE :
            follow = q->start_state->next;
      }

      if ( block_type == OPT || block_type == CLOSURE || block_type == POS_CLOSURE )
      {
            TAB;
            fprintf(output, "else {\n");
            need_right_curly++;
            TAB;
            fprintf(output, "if (");
            /* what follows the block? */
            q->start_state->visited = 1;
            q->start_state->lookahead = gen_prediction_expr(NULL, follow);
            q->start_state->visited = 0;
            fprintf(output, " ) {\n");
            if ( block_type != OPT )
            {
                  tabs++; TAB;
                  fprintf(output, "_done = 1;\n");
                  tabs--;
            }
            TAB;
            fprintf(output, "}\n");
      }

      /* Generate error clause */
      TAB;
      fprintf(output, "else {\n");
      /* generate the _GUESS_FAIL even if no (..)? found because calling
       * routine may be using STreeTest()
       */
      tabs++;
      TAB;
      if ( GenCPP ) fprintf(output, "if ( guessing ) _GUESS_FAIL;\n");
      else fprintf(output, "if ( _parser->guessing ) _GUESS_FAIL;\n");
      TAB;
      if ( GenCPP ) fprintf(output, "no_viable_alt(\"%s\", _t);\n", current_rule);
      else fprintf(output, "no_viable_alt(_parser, \"%s\", _t);\n", current_rule);
      tabs--;
      TAB;
      fprintf(output, "}\n");
      if ( transform ) { TAB; fprintf(output, " _tresult = _r;\n"); }

      for (;need_right_curly>0; need_right_curly--)
      {
            TAB;
            fprintf(output, "}\n");
      }

      switch ( block_type ) {
      case BLOCK :
            break;
      case CLOSURE :
            tabs--;
            TAB; fprintf(output, "}\n");
/*          if ( transform ) fprintf(output, " _tresult = _r;\n"); */
            TAB; fprintf(output, "}\n");
            break;
      case POS_CLOSURE :
            tabs--;
            TAB;
            fprintf(output, "} while ( !_done );\n");
/*          if ( transform ) { TAB; fprintf(output, " _tresult = _r;\n"); } */
            TAB;
            fprintf(output, "}\n");
            break;
      case PRED_OP :
            TAB;
            fprintf(output, "_RESTORE;\n");
/*          if ( transform ) { TAB; fprintf(output, " _tresult = _r;\n"); } */
            TAB; fprintf(output, "}\n");
            TAB; fprintf(output, "_GUESS_DONE;\n");
            break;
      }

      test_block_consistency(q, block_type);
}

void
#ifdef __USE_PROTOS
gen_alt( AST *t )
#else
gen_alt( t )
AST *t;
#endif
{
      require(t!=NULL && t->token==ALT, "gen_alt: invalid alt");

      t = t->down;
      if ( t==NULL ) return;
      if ( t->token==Action ) t->init_action = 1;
      gen_tree_pattern(t);

      /* find last element of alternative to see if it's a simple token */
      while ( t->right!=NULL ) { t = t->right; }
      if ( t->down==NULL && (t->token == Token || t->token == WILD) )
            { TAB; go_right(1); }
}

void
#ifdef __USE_PROTOS
gen_tree_pattern( AST *t )
#else
gen_tree_pattern( t )
AST *t;
#endif
{
      while ( t != NULL )
      {
            /* could be root of a tree, check it */
            if ( t->down != NULL && (t->token==Token||t->token==WILD) ) {
                  TAB;
                  fprintf(output, "{_SAVE; TREE_CONSTR_PTRS;\n");
            }
            gen_element(t);
            if ( t->down != NULL ) {
                  if ( t->token == Token || t->token==WILD )
                  {
                        gen_tree_pattern(t->down);    /* only token/wildcard can be root of tree */
                        TAB;
                        fprintf(output, "_RESTORE;");
                        if ( transform ) fprintf(output, " _tresult = _r;");
                        fprintf(output, "\n");
                        TAB; fprintf(output, "}\n");
                        /* link in result of #(...) */
                        if ( transform && !whichRule->no_copy ) {
                              TAB; fprintf(output, "_mkchild(&_r,&_s,&_e,_tresult);\n");
                        }
                        TAB; go_right(1);
                  }
            }
            t = t->right;
      }
}

void
#ifdef __USE_PROTOS
gen_element( AST *t )
#else
gen_element( t )
AST *t;
#endif
{
      char *res;
      require(t!=NULL, "gen_element: NULL tree pointer");

      switch ( t->token )
      {
          case Token :
                  TAB;
                  if ( t->upper_range!=0 )
                        fprintf(output, "_MATCHRANGE(%s,%s);",
                                    t->text, token_dict[t->upper_range]);
                  else fprintf(output, "_MATCH(%s);", t->text);
                  fprintf(output, "\n");
                  /* Make copy of token if transform && (copy or (labeled&&!copy)) */
                  if ( transform && (t->label[0]!='\0'||!t->no_copy) ) {
                        TAB;
                        if ( GenCPP )
                              fprintf(output, "_tresult=_t->shallowCopy();\n");
                        else
                              fprintf(output, "_tresult=ast_dup_node(_t);\n");
                  }
                  if ( transform && !t->no_copy ) {
                        if ( t->is_root )
                              fprintf(output, " _mkroot(&_r,&_s,&_e,_tresult);\n");
                        else
                              fprintf(output, " _mkchild(&_r,&_s,&_e,_tresult);\n");
                  }
                  /* Do Label if any */
                  if ( transform  ) {           /* label is output, label_in is input */
                        if ( t->label[0]!='\0' )
                        {
                              TAB;
                              fprintf(output,
                                          "%s=(SORAST *)_tresult; %s_in=(SORAST *)_t;\n",
                                          t->label,t->label);
                        }
                  } else {
                        if ( t->label[0]!='\0' )
                              { TAB; fprintf(output, "%s=(SORAST *)_t;\n", t->label); }
                  }
                  /* Move tree parser pointer */
                  if ( t->down != NULL ) { TAB; go_down(1); }
                  else if ( t->right != NULL ) { TAB; go_right(1); }
                  break;
            case WILD :
                  TAB;
                  fprintf(output, "_WILDCARD;");
                  /* Make copy of token or tree if transform */
                  if ( transform ) {
                        TAB;
                        if ( GenCPP )
                              fprintf(output, "_tresult=_t->deepCopy();");
                        else
                              fprintf(output, "_tresult=ast_dup(_t);");
                        /* wildcard can't be root, must be child */
                        if ( !t->no_copy ) {
                              if ( t->is_root )
                                    fprintf(output, " _mkroot(&_r,&_s,&_e,_tresult);");
                              else
                                    fprintf(output, " _mkchild(&_r,&_s,&_e,_tresult);");
                        }
                  }
                  fprintf(output, "\n");
                  if ( transform  ) {
                        if ( t->label[0]!='\0' )
                        {
                              TAB;
                              fprintf(output,
                                          "%s=(SORAST *)_tresult; %s_in=(SORAST *)_t;\n",
                                          t->label,t->label);
                        }
                  } else {
                        if ( t->label[0]!='\0' )
                              { TAB; fprintf(output, "%s=(SORAST *)_t;\n", t->label); }
                  }
                  if ( t->down != NULL ) { TAB; go_down(1); }
                  else if ( t->right != NULL ) { TAB; go_right(1); }
                  break;
            case NonTerm :
                  TAB;
                  /* For nontransform mode, do labels first */
                  if (t->label[0]!='\0')
                        fprintf(output, "%s=(SORAST *)_t; ", t->label);
                  if ( t->out ) {
                        if ( t->in ) fprintf(output, "%s=", t->down->right->text);
                        else fprintf(output, "%s=", t->down->text);
                  }
                  fprintf(output, "%s%s", Prefix, t->text);
                  if ( transform ) res = ", &_tresult"; else res = "";
                  if ( GenCPP ) {
                        if ( t->in ) fprintf(output, "(&_t%s, %s);",
                                                       res, t->down->text);
                        else fprintf(output, "(&_t%s);", res);
                  }
                  else {
                        if ( t->in ) fprintf(output, "(_parser, &_t%s, %s);",
                                                       res, t->down->text);
                        else fprintf(output, "(_parser, &_t%s);", res);
                  }
                  fprintf(output, "\n");
                  if (transform && t->label[0]!='\0')
                        {
                              TAB;
                              fprintf(output, "%s=(SORAST *)_tresult;\n", t->label);
                        }
                  /* Link in result of rule */
                  if ( transform&&!t->no_copy ) {
                        TAB;
                        fprintf(output, "_mkchild(&_r,&_s,&_e,_tresult);\n");
                  }
                  break;
            case Action :
                  if ( !t->init_action && found_guess_block ) {
                        TAB;
                        if ( GenCPP ) fprintf(output, "if ( !guessing ) {\n");
                        else fprintf(output, "if ( !_parser->guessing ) {\n");
                  }
                  dumpAction(t->action, output, tabs, 0, 0, 1);
                  if ( !t->init_action && found_guess_block ) {TAB; fprintf(output, "}\n");}
                  break;
            case CLOSURE :
                  gen_block(t->down, CLOSURE);
                  break;
            case POS_CLOSURE :
                  gen_block(t->down, POS_CLOSURE);
                  break;
            case OPT :
                  gen_block(t->down, OPT);
                  break;
            case BLOCK :
                  gen_block(t, BLOCK);
                  break;
            case PRED_OP :
                  require(t->up!=NULL, "define_labels_in_element: GLA is broken");
                  if ( t->up->down==t ) {
                        if ( t->down->token == BLOCK ) gen_block(t->down, PRED_OP);
                  }
                  else if ( t->up->down->token==Action && t->up->down->right==t ) {
                        if ( t->down->token == BLOCK ) gen_block(t->down, PRED_OP);
                  }
                  else {
                        warnFL("predicate not at beginning of alternative; ignored",
                                 FileStr[t->file], t->line);
                  }
                  break;
            default :
                  fatal(eMsgd("invalid elemental node type: %d", t->token));
      }
}

/* walk the block of a rule and define all labels to be "SORAST *label_i" */
void
#ifdef __USE_PROTOS
define_labels_in_block( AST *t )
#else
define_labels_in_block( t )
AST *t;
#endif
{
      require(t!=NULL, "define_labels_in_block: NULL tree pointer");
      require(t->token==BLOCK, "define_labels_in_block: invalid block");
      t = t->down;
      while ( t!=NULL )
      {
            define_labels_in_alt(t);
            t = t->right;
      }
}

void
#ifdef __USE_PROTOS
define_labels_in_alt( AST *t )
#else
define_labels_in_alt( t )
AST *t;
#endif
{
      require(t!=NULL, "define_labels_in_alt: NULL tree pointer");
      require(t->token==ALT, "gen_alt: invalid alt");

      define_labels_in_tree(t->down);
}

void
#ifdef __USE_PROTOS
define_labels_in_tree( AST *t )
#else
define_labels_in_tree( t )
AST *t;
#endif
{
      while ( t != NULL )
      {
            define_labels_in_element(t);
            /* could be root of a tree, check it */
            if ( t->down != NULL ) {
                  if ( t->token == Token || t->token==WILD )
                  {
                        define_labels_in_tree(t->down);
                  }
            }
            t = t->right;
      }
}

void
#ifdef __USE_PROTOS
define_labels_in_element( AST *t )
#else
define_labels_in_element( t )
AST *t;
#endif
{
      require(t!=NULL, "define_labels_in_element: NULL tree pointer");
      switch ( t->token )
      {
          case Token :
            case WILD :
            case NonTerm :
                  if ( t->label[0]!='\0' ) {
                        SymEntry *s;
                        s = (SymEntry *) hash_get(symbols, t->label);
                        require(s!=NULL, "define_labels_in_element: sym tab broken");
                        if ( s->token==LABEL && !s->defined ) {
                              s->defined = 1;
                              TAB;
                              fprintf(output, "SORAST *%s=NULL", t->label);
                              if ( transform ) fprintf(output, ",*%s_in=NULL", t->label);
                              fprintf(output, ";\n");
                              /* track which ones we define so that we can undefine
                               * them for the next rule
                               */
                              list_add(&labels_for_func, (void *)s);
                        }
                  }
                  break;
            case Action :
                  break;
            case CLOSURE :
            case POS_CLOSURE :
                  define_labels_in_block(t->down);
                  break;
            case PRED_OP :
                  if ( t->down->token != Action )
                  {
                        define_labels_in_block(t->down);
                  }
                  break;
            case OPT :
                  define_labels_in_block(t->down);
                  break;
            case BLOCK :
                  define_labels_in_block(t);
                  break;
      }
}

/* dump action 's' to file 'output' starting at "local" tab 'tabs'
   Dump line information in front of action if GenLineInfo is set
   If file == -1 then GenLineInfo is ignored.
   The user may redefine the LineInfoFormatStr to his/her liking
   most compilers will like the default, however.

   June '93; changed so that empty lines are left alone so that
   line information is correct for the compiler/debuggers.
*/
void
#ifdef __USE_PROTOS
dumpAction( char *s, FILE *output, int tabs, int file, int line, int final_newline )
#else
dumpAction( s, output, tabs, file, line, final_newline )
char *s;
FILE *output;
int tabs;
int file;
int line;
int final_newline;
#endif
{
    int inDQuote, inSQuote;
    require(s!=NULL,          "dumpAction: NULL action");
    require(output!=NULL,     eMsg1("dumpAction: output FILE is NULL for %s",s));

/*    if ( GenLineInfo && file != -1 )
      {
            fprintf(output, LineInfoFormatStr, line, FileStr[file]);
      }*/
    PastWhiteSpace( s );
      /* don't print a tab if first non-white char is a # (preprocessor command) */
      if ( *s!='#' ) {TAB;}
    inDQuote = inSQuote = 0;
    while ( *s != '\0' )
    {
        if ( *s == '\\' )
        {
            putc( *s++, output ); /* Avoid '"' Case */
            if ( *s == '\0' ) return;
            if ( *s == '\'' ) putc( *s++, output );
            if ( *s == '\"' ) putc( *s++, output );
        }
        if ( *s == '\'' )
        {
            if ( !inDQuote ) inSQuote = !inSQuote;
        }
        if ( *s == '"' )
        {
            if ( !inSQuote ) inDQuote = !inDQuote;
        }
        if ( *s == '\n' )
        {
            putc('\n', output);
                  s++;
            while (*s == '\n') {
               putc('\n', output);
               s++;
            }
            PastWhiteSpace( s );
            if ( *s == '}' )
            {
                --tabs;
                        TAB;
                putc( *s++, output );
                continue;
            }
            if ( *s == '\0' ) return;
                  if ( *s != '#' )  /* #define, #endif etc.. start at col 1 */
            {
                        TAB;
                  }
        }
        if ( *s == '}' && !(inSQuote || inDQuote) )
        {
            --tabs;            /* Indent one fewer */
        }
        if ( *s == '{' && !(inSQuote || inDQuote) )
        {
            tabs++;            /* Indent one more */
        }
        putc( *s, output );
        s++;
    }
    if ( final_newline ) putc('\n', output);
}

char *
#ifdef __USE_PROTOS
find_predicate( AST *t )
#else
find_predicate( t )
AST *t;
#endif
{
      if ( t==NULL ) return NULL;
      if ( t->token == Action )
      {
            if ( t->right!=NULL && t->right->token==PRED_OP && t->right->down->token!=BLOCK )
            {
                  return t->right->down->action;
            }
      }
      else if ( t->token == PRED_OP && t->down->token!=BLOCK )
      {
            return t->down->action;
      }
      return NULL;
}

/* Given a pointer to a tree pattern element (Token, BLOCK, etc...),
 * generate an expression that predicts when that path would match.
 */
set
#ifdef __USE_PROTOS
gen_prediction_expr( AST *alt, GLA *t )
#else
gen_prediction_expr( alt, t )
AST *alt;
GLA *t;
#endif
{
      char *sempred;
      set a, rs;
      int tok, first=1, num_on_line=0;
      require(alt==NULL||alt->token==ALT,
                  "gen_prediction_expr: AST node is invalid");

      a = Lookahead(t);
      rs = set_dup(a);

      /* if this production is a guess block, then test return value of setjmp() */

    /* MR21 Problem reported by Peter Keller
       THM: Sor doesn't see predicate because of intervening action.
       
    */

    if (alt != NULL) {
        AST* cursor;
        for (cursor = alt->down;
             cursor != NULL && Action == cursor->token;
             cursor = cursor->right) {
                  /* nothing */ 
        }
        if (cursor != NULL &&
            cursor->token == PRED_OP &&
            cursor->down->token == BLOCK) {
            fprintf(output," !_gv &&");
        }
    }

#if 0
                /* The old code which was replaced */

      if ( alt!=NULL && alt->down!=NULL && alt->down->token==PRED_OP &&
             alt->down->down->token==BLOCK ) fprintf(output, " !_gv &&");

#endif

      /* handle end of input first */
      if ( set_el(end_of_input, a) )
      {
            fprintf(output, " _t==NULL");
            set_rm(end_of_input, a);
            if ( !set_nil(a) ) fprintf(output, " ||");
      }
      else if ( set_el(wild_card, a) )
      {
            fprintf(output, " _t!=NULL");
            if ( alt!=NULL ) {
                  sempred = find_predicate(alt->down);
                  if ( sempred!=NULL ) fprintf(output, " && (%s)", sempred);
            }
            set_free(a);
            return rs;
      }
      else
      {
            fprintf(output, " _t!=NULL");
            if ( !set_nil(a) ) fprintf(output, " &&");
      }

      if ( set_nil(a) ) { set_free(a); return rs; }

      fprintf(output, " (");
      while ( !set_nil(a) )
      {
            tok = set_int(a);
            set_rm(tok, a);
            if ( first ) first = 0;
            else fprintf(output, "||");
            if ( num_on_line>=2 ) {num_on_line=0; fprintf(output,"\n"); TAB;}
            else num_on_line++;
            if ( tok==wild_card ) fprintf(output, "_t!=NULL");
            else if ( token_dict[tok]==0 )
            {
                  if ( GenCPP )
                        fprintf(output, "_t->type()==UNDEFINED_TOKEN");
                  else
                        fprintf(output, "_t->token==UNDEFINED_TOKEN");
            }
            else
            {
                  if ( GenCPP )
                        fprintf(output, "_t->type()==%s", token_dict[tok]);
                  else
                        fprintf(output, "_t->token==%s", token_dict[tok]);
            }
      }
      fprintf(output, ")");

      if ( alt!=NULL ) {
            sempred = find_predicate(alt->down);
            if ( sempred!=NULL ) fprintf(output, " && (%s)", sempred);
      }
      set_free(a);
      return rs;
}

/* Find all return types/parameters that require structs and def
 * all rules with ret types.
 */
void
#ifdef __USE_PROTOS
GenRulePrototypes( FILE *f, int tabs )
#else
GenRulePrototypes( f, tabs )
FILE *f;
int tabs;
#endif
{
      AST *p;
      SymEntry *s;

      for (p=rules; p!=NULL; p=p->right)
      {
            int i;
            s = (SymEntry *) hash_get(symbols, p->text);
            require(s!=NULL, "GenRulePrototypes: sym tab broken");

            for (i=1; i<=tabs; i++) fprintf(f, "\t");
            GenRulePrototype(f, p, s, 1);
      }
}

void
#ifdef __USE_PROTOS
GenRulePrototype(FILE *f, AST *p, SymEntry *s, int decl_not_def)
#else
GenRulePrototype(f, p, s, decl_not_def)
FILE *f;
SymEntry *s;
AST *p;
int decl_not_def;
#endif
{
      require(s!=NULL&&s->definition!=NULL, "GenRulePrototype: no def for rule");

      if ( GenCPP )
      {
            if ( s->rt != NULL )
                  DumpType(s->rt, f, FileStr[s->definition->file], s->definition->line);
            else fprintf(f, "void");
            if ( decl_not_def )
                  fprintf(f, " %s(SORASTBase **_root%s",
                              p->text,
                              transform?", SORASTBase **_result":"");
            else
                  fprintf(f, " %s::%s(SORASTBase **_root%s",
                              CurClassName,
                              p->text,
                              transform?", SORASTBase **_result":"");
            if ( s->args != NULL ) fprintf(f, ",%s", s->args);
            fprintf(f, ")");
            if ( decl_not_def ) fprintf(f, ";");
            fprintf(f, "\n");
            return;
      }

      if ( decl_not_def ) fprintf(f, "extern ");
      if ( GenAnsiProtos && GenKRProtos ) fprintf(f, "\n#ifdef __USE_PROTOS\n");
      if ( GenAnsiProtos )
      {
            if ( s->rt != NULL )
                  DumpType(s->rt, f, FileStr[s->definition->file], s->definition->line);
            else fprintf(f, "void");
            fprintf(f, " %s%s(STreeParser *_parser, SORAST **_root%s",
                        Prefix,
                        p->text,
                        transform?", SORAST **_result":"");
            if ( s->args != NULL ) fprintf(f, ",%s", s->args);
            fprintf(f, ")");
            if ( decl_not_def ) fprintf(f, ";");
            fprintf(f, "\n");
      }
      if ( GenAnsiProtos && GenKRProtos ) fprintf(f, "#else\n");
      if ( GenKRProtos )
      {
            if ( s->rt != NULL )
                  DumpType(s->rt, f, FileStr[s->definition->file], s->definition->line);
            else fprintf(f, "void");
            if ( decl_not_def) fprintf(f, " %s%s();\n", Prefix, p->text);
            else
            {
                  fprintf(f, " %s%s(_parser, _root%s",
                              Prefix, p->text,transform?", _result":"");
                  if ( s->args!=NULL ) fprintf(f, ",");
                  DumpListOfParmNames(s->args, f);
                  fprintf(f, ")\n");
                  fprintf(f, "STreeParser *_parser;\n");
                  fprintf(f, "SORAST **_root%s;\n", transform?", **_result":"");
                  DumpOldStyleParms(s->args, f);
            }
      }
      if ( GenAnsiProtos && GenKRProtos ) fprintf(f, "#endif\n");
}

/*
 * For each referenced token, generate a #define in a file defined in
 * 'def_token_file'.
 */
void
#ifdef __USE_PROTOS
gen_tokens_file( void )
#else
gen_tokens_file( )
#endif
{
      FILE *f;
      ListNode *p;

      if ( def_token_file==NULL ) return;

      f = fopen(def_token_file, "w");
      if ( f==NULL )
      {
            errNoFL(eMsg1("cannot write token definition file %s", def_token_file));
            return;
      }
#ifdef SPECIAL_FOPEN
       special_fopen_actions(def_token_file);
#endif

      gen_info_hdr(f);
      fprintf(f, "\n");
      for (p = token_list->next; p!=NULL; p=p->next)
      {
            SymEntry *t = (SymEntry *) p->elem;
            fprintf(f, "#define %s %d\n", t->str, t->token_type);
      }
      fclose(f);
}

AST *
#ifdef __USE_PROTOS
first_guess_block(AST *q)
#else
first_guess_block(q)
AST *q;
#endif
{
      require(q!=NULL&&q->token==ALT, "first_guess_block: non-ALT ptr");

      if ( q->down!=NULL )
      {
            if ( (q->down->token==PRED_OP && q->down->down!=NULL &&
                    q->down->down->token==BLOCK) )
            {
                  return q->down;
            }
            else if (q->down->token==Action && q->down->right!=NULL &&
                    q->down->right->token==PRED_OP && q->down->right->down!=NULL &&
                    q->down->right->down->token==BLOCK)
            {
                  return q->down->right;
            }
            else return NULL;
      }
      return NULL;
}

void
#ifdef __USE_PROTOS
code_for_guess_block( AST *t, int *guess_block_in_prev_alt )
#else
code_for_guess_block( t, guess_block_in_prev_alt )
AST *t;
int *guess_block_in_prev_alt;
#endif
{
      if ( found_guess_block )
      {
            /* if previous alt had a guess block, check to turn it off */
            if ( *guess_block_in_prev_alt )
            {
                  TAB;
                  if ( GenCPP ) fprintf(output, "if ( guessing ) _GUESS_DONE;\n");
                  else fprintf(output, "if ( _parser->guessing ) _GUESS_DONE;\n");
            }
            /* if current alt has a guess block... */
            if ( first_guess_block(t)!=NULL )
            {
                  TAB;
                  fprintf(output, "_GUESS;\n");
                  *guess_block_in_prev_alt = 1;
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index