home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 379a.lha / p2c1_13a / src / src.zoo / parse4.c < prev    next >
C/C++ Source or Header  |  1990-03-11  |  35KB  |  1,289 lines

  1. /* "p2c", a Pascal to C translator.
  2.    Copyright (C) 1989 David Gillespie.
  3.    Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation (any version).
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. GNU General Public License for more details.
  13.  
  14. You should have received a copy of the GNU General Public License
  15. along with this program; see the file COPYING.  If not, write to
  16. the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  17.  
  18. #define PROTO_PARSE4_C
  19. #include "trans.h"
  20.  
  21. extern Stmt bogusreturn;
  22. extern Meaning *outcontext;
  23. extern Strlist *includedfiles;
  24.  
  25. #define addstmt(kind)   \
  26.     *spp = sp = makestmt(kind),   \
  27.     spp = &(sp->next)
  28.  
  29. #define SF_FUNC    0x1
  30.  
  31. #define BR_NEVER        0x1     /* never use braces */
  32. #define BR_FUNCTION     0x2     /* function body */
  33. #define BR_THENPART     0x4     /* before an "else" */
  34. #define BR_ALWAYS       0x8     /* always use braces */
  35. #define BR_REPEAT       0x10    /* "do-while" loop */
  36. #define BR_TRY          0x20    /* in a recover block */
  37. #define BR_ELSEPART     0x40    /* after an "else" */
  38. #define BR_CASE         0x80    /* case of a switch stmt */
  39.  
  40. void initfilevars(mp, sppp, exbase)
  41. Meaning *mp;
  42. Stmt ***sppp;
  43. Expr *exbase;
  44. {
  45.     Stmt *sp;
  46.     Type *tp;
  47.     Expr *ex;
  48.  
  49.     while (mp) {
  50.     if ((mp->kind == MK_VAR && mp->refcount > 0 && !mp->istemporary) ||
  51.         mp->kind == MK_FIELD) {
  52.         tp = mp->type;
  53.         if (isfiletype(tp)) {
  54.         mp->refcount++;
  55.         sp = makestmt(SK_ASSIGN);
  56.         sp->next = **sppp;
  57.         **sppp = sp;
  58.         if (exbase)
  59.             ex = makeexpr_dot(copyexpr(exbase), mp);
  60.         else
  61.             ex = makeexpr_var(mp);
  62.         sp->exp1 = makeexpr_assign(copyexpr(ex), makeexpr_nil());
  63.         } else if (tp->kind == TK_RECORD) {
  64.         if (exbase)
  65.             ex = makeexpr_dot(copyexpr(exbase), mp);
  66.         else
  67.             ex = makeexpr_var(mp);
  68.         initfilevars(tp->fbase, sppp, ex);
  69.         freeexpr(ex);
  70.         } else if (tp->kind == TK_ARRAY) {
  71.         while (tp->kind == TK_ARRAY)
  72.             tp = tp->basetype;
  73.         if (isfiletype(tp))
  74.             note(format_s("Array of files %s should be initialized [257]",
  75.                   mp->name));
  76.         }
  77.     }
  78.     mp = mp->cnext;
  79.     }
  80. }
  81.  
  82.  
  83.  
  84.  
  85.  
  86. Static Stmt *p_body()
  87. {
  88.     Stmt *sp, **spp, *spbody, **sppbody, *spbase, *thereturn;
  89.     Meaning *mp;
  90.     Expr *ex;
  91.     int haspostamble;
  92.     long saveserial;
  93.  
  94.     if (verbose)
  95.     fprintf(logf, "%s, %d/%d: Translating %s (in %s)\n",
  96.         infname, inf_lnum, outf_lnum,
  97.         curctx->name, curctx->ctx->name);
  98.     notephase = 1;
  99.     spp = &spbase;
  100.     addstmt(SK_HEADER);
  101.     sp->exp1 = makeexpr_var(curctx);
  102.     checkkeyword(TOK_INLINE);
  103.     if (curtok != TOK_END && curtok != TOK_BEGIN && curtok != TOK_INLINE) {
  104.     if (curctx->kind == MK_FUNCTION || curctx->anyvarflag)
  105.         wexpecttok(TOK_BEGIN);
  106.     else
  107.         wexpecttok(TOK_END);
  108.     skiptotoken2(TOK_BEGIN, TOK_END);
  109.     }
  110.     if (curtok == TOK_END) {
  111.     gettok();
  112.     spbody = NULL;
  113.     } else {
  114.     spbody = p_stmt(NULL, SF_FUNC);  /* parse the procedure/program body */
  115.     }
  116.     if (curtok == TOK_IDENT && curtokmeaning == curctx) {
  117.     gettok();    /* Modula-2 */
  118.     }
  119.     notephase = 2;
  120.     saveserial = curserial;
  121.     curserial = 10000;
  122.     if (curctx->kind == MK_FUNCTION) {     /* handle copy parameters */
  123.         for (mp = curctx->type->fbase; mp; mp = mp->xnext) {
  124.             if (!mp->othername && mp->varstructflag) {
  125.                 mp->othername = stralloc(format_s(name_COPYPAR, mp->name));
  126.                 mp->rectype = mp->type;
  127.                 addstmt(SK_ASSIGN);
  128.                 sp->exp1 = makeexpr_assign(makeexpr_var(mp), 
  129.                                            makeexpr_name(mp->othername, mp->rectype));
  130.                 mp->refcount++;
  131.             } else if (mp->othername) {
  132.                 if (checkvarchanged(spbody, mp)) {
  133.                     addstmt(SK_ASSIGN);
  134.                     sp->exp1 = makeexpr_assign(makeexpr_var(mp),
  135.                                                makeexpr_hat(makeexpr_name(mp->othername,
  136.                                                                           mp->rectype), 0));
  137.                     mp->refcount++;
  138.                 } else {           /* don't need to copy it after all */
  139.                     strchange(&mp->othername, mp->name);
  140.                     ex = makeexpr_var(mp);
  141.                     ex->val.type = mp->rectype;
  142.                     replaceexpr(spbody, makeexpr_var(mp), makeexpr_hat(ex, 0));
  143.                 }
  144.             }
  145.         }
  146.     }
  147.     for (mp = curctx->cbase; mp; mp = mp->cnext) {
  148.     if (mp->kind == MK_LABEL && mp->val.i) {
  149.         addstmt(SK_IF);
  150.         sp->exp1 = makeexpr_bicall_1("setjmp", tp_int,
  151.                      makeexpr_var(mp->xnext));
  152.         sp->stm1 = makestmt(SK_GOTO);
  153.         sp->stm1->exp1 = makeexpr_name(format_s(name_LABEL, mp->name),
  154.                        tp_integer);
  155.     }
  156.     }
  157.     *spp = spbody;
  158.     sppbody = spp;
  159.     while (*spp)
  160.         spp = &((*spp)->next);
  161.     haspostamble = 0;
  162.     initfilevars(curctx->cbase, &sppbody, NULL);
  163.     for (mp = curctx->cbase; mp; mp = mp->cnext) {
  164.         if (mp->kind == MK_VAR && mp->refcount > 0 && isfiletype(mp->type) &&
  165.              !mp->istemporary) {
  166.             if (curctx->kind != MK_MODULE || curctx->anyvarflag) {
  167.                 addstmt(SK_IF);                    /* close file variables */
  168.                 sp->exp1 = makeexpr_rel(EK_NE, makeexpr_var(mp), makeexpr_nil());
  169.                 sp->stm1 = makestmt(SK_ASSIGN);
  170.                 sp->stm1->exp1 = makeexpr_bicall_1("fclose", tp_void, makeexpr_var(mp));
  171.             }
  172.             haspostamble = 1;
  173.         }
  174.     }
  175.     thereturn = &bogusreturn;
  176.     if (curctx->kind == MK_FUNCTION && curctx->type->basetype != tp_void) {
  177.         if ((haspostamble || !checkreturns(&spbase, 1)) &&
  178.             curctx->cbase->refcount > 0) {      /* add function return code */
  179.             addstmt(SK_RETURN);
  180.             sp->exp1 = makeexpr_var(curctx->cbase);
  181.         }
  182.         thereturn = NULL;
  183.     } else if (curctx->kind == MK_MODULE && curctx->anyvarflag) {
  184.         addstmt(SK_ASSIGN);
  185.         sp->exp1 = makeexpr_bicall_1("exit", tp_void, makeexpr_long(0));
  186.         thereturn = NULL;
  187.     }
  188.     if (debug>2) { fprintf(outf, "calling fixblock/usecommas on:\n"); dumpstmt(spbase, 5); }
  189.     curserial = saveserial;
  190.     sp = makestmt(SK_BODY);
  191.     sp->stm1 = spbase;
  192.     fixblock(&sp, thereturn);           /* finishing touches to statements and expressions */
  193.     spbase = sp->stm1;
  194.     FREE(sp);
  195.     if (usecommas != 1)
  196.         checkcommas(&spbase);    /* unroll ugly EK_COMMA and EK_COND expressions */
  197.     if (debug>1) { fprintf(outf, "p_body returns:\n"); dumpstmt(spbase, 5); }
  198.     notephase = 0;
  199.     return spbase;
  200. }
  201.  
  202.  
  203.  
  204.  
  205. #define checkWord()  if (anywords) output(" "); anywords = 1
  206.  
  207. Static void out_function(func)
  208. Meaning *func;
  209. {
  210.     Meaning *mp;
  211.     Symbol *sym;
  212.     int opts, anywords, spacing, saveindent;
  213.  
  214.     if (func->varstructflag) {
  215.         makevarstruct(func);
  216.     }
  217.     if (collectnest) {
  218.     for (mp = func->cbase; mp; mp = mp->cnext) {
  219.         if (mp->kind == MK_FUNCTION && mp->isforward) {
  220.         forward_decl(mp, 0);
  221.         }
  222.     }
  223.     for (mp = func->cbase; mp; mp = mp->cnext) {
  224.         if (mp->kind == MK_FUNCTION && mp->type) {
  225.         pushctx(mp);
  226.         out_function(mp);    /* generate the sub-procedures first */
  227.         popctx();
  228.         }
  229.     }
  230.     }
  231.     spacing = functionspace;
  232.     for (mp = func; mp->ctx->kind == MK_FUNCTION; mp = mp->ctx) {
  233.         if (spacing > minfuncspace)
  234.             spacing--;
  235.     }
  236.     outsection(spacing);
  237.     flushcomments(&func->comments, -1, 0);
  238.     if (usePPMacros == 1) {
  239.         forward_decl(func, 0);
  240.         outsection(minorspace);
  241.     }
  242.     opts = ODECL_HEADER;
  243.     anywords = 0;
  244.     if (func->namedfile) {
  245.     checkWord();
  246.     if (useAnyptrMacros || ansiC < 2)
  247.         output("Inline");
  248.     else
  249.         output("inline");
  250.     }
  251.     if (!func->exported) {
  252.     if (func->ctx->kind == MK_FUNCTION) {
  253.         if (useAnyptrMacros) {
  254.         checkWord();
  255.         output("Local");
  256.         } else if (use_static) {
  257.         checkWord();
  258.         output("static");
  259.         }
  260.     } else if ((findsymbol(func->name)->flags & NEEDSTATIC) ||
  261.            (use_static != 0 && !useAnyptrMacros)) {
  262.         checkWord();
  263.         output("static");
  264.     } else if (useAnyptrMacros) {
  265.         checkWord();
  266.         output("Static");
  267.     }
  268.     }
  269.     if (func->type->basetype != tp_void || ansiC != 0) {
  270.     checkWord();
  271.         outbasetype(func->type, 0);
  272.     }
  273.     if (anywords) {
  274.         if (newlinefunctions)
  275.             opts |= ODECL_FUNCTION;
  276.         else
  277.             output(" ");
  278.     }
  279.     outdeclarator(func->type, func->name, opts);
  280.     if (fullprototyping == 0) {
  281.     saveindent = outindent;
  282.     moreindent(argindent);
  283.         out_argdecls(func->type);
  284.     outindent = saveindent;
  285.     }
  286.     for (mp = func->type->fbase; mp; mp = mp->xnext) {
  287.         if (mp->othername && strcmp(mp->name, mp->othername))
  288.             mp->wasdeclared = 0;    /* make sure we also declare the copy */
  289.     }
  290.     func->wasdeclared = 1;
  291.     outcontext = func;
  292.     out_block((Stmt *)func->val.i, BR_FUNCTION, 10000);
  293.     if (useundef) {
  294.     anywords = 0;
  295.     for (mp = func->cbase; mp; mp = mp->cnext) {
  296.         if (mp->kind == MK_CONST &&
  297.         mp->isreturn) {    /* the was-#defined flag */
  298.         if (!anywords)
  299.             outsection(minorspace);
  300.         anywords++;
  301.         output(format_s("#undef %s\n", mp->name));
  302.         sym = findsymbol(mp->name);
  303.         sym->flags &= ~AVOIDNAME;
  304.         }
  305.     }
  306.     }
  307.     if (conserve_mem) {
  308.     free_stmt((Stmt *)func->val.i);   /* is this safe? */
  309.     func->val.i = 0;
  310.     forget_ctx(func, 0);
  311.     }
  312.     outsection(spacing);
  313. }
  314.  
  315.  
  316.  
  317.  
  318. void movetoend(mp)
  319. Meaning *mp;
  320. {
  321.     Meaning **mpp;
  322.  
  323.     if (mp->ctx != curctx) {
  324.         intwarning("movetoend", "curctx is wrong [268]");
  325.     } else {
  326.         mpp = &mp->ctx->cbase;     /* move a meaning to end of its parent context */
  327.         while (*mpp != mp) {
  328.         if (!*mpp) {
  329.         intwarning("movetoend", "meaning not on its context list [269]");
  330.         return;
  331.         }
  332.             mpp = &(*mpp)->cnext;
  333.     }
  334.         *mpp = mp->cnext;    /* Remove from present position in list */
  335.         while (*mpp)
  336.             mpp = &(*mpp)->cnext;
  337.         *mpp = mp;           /* Insert at end of list */
  338.         mp->cnext = NULL;
  339.         curctxlast = mp;
  340.     }
  341. }
  342.  
  343.  
  344.  
  345. Static void scanfwdparams(mp)
  346. Meaning *mp;
  347. {
  348.     Symbol *sym;
  349.  
  350.     mp = mp->type->fbase;
  351.     while (mp) {
  352.     sym = findsymbol(mp->name);
  353.     sym->flags |= FWDPARAM;
  354.     mp = mp->xnext;
  355.     }
  356. }
  357.  
  358.  
  359.  
  360. Static void p_function(isfunc)
  361. int isfunc;
  362. {
  363.     Meaning *func;
  364.     Type *type;
  365.     Stmt *sp;
  366.     Strlist *sl, *comments, *savecmt;
  367.     int initializeattr = 0, isinline = 0;
  368.  
  369.     if ((sl = strlist_find(attrlist, "INITIALIZE")) != NULL) {
  370.     initializeattr = 1;
  371.     strlist_delete(&attrlist, sl);
  372.     }
  373.     if ((sl = strlist_find(attrlist, "OPTIMIZE")) != NULL &&
  374.     sl->value != -1 &&
  375.     !strcmp((char *)(sl->value), "INLINE")) {
  376.     isinline = 1;
  377.     strlist_delete(&attrlist, sl);
  378.     }
  379.     ignore_attributes();
  380.     comments = extractcomment(&curcomments, -1, curserial);
  381.     changecomments(comments, -1, -1, -1, 0);
  382.     if (curctx->kind == MK_FUNCTION) {    /* sub-procedure */
  383.     savecmt = curcomments;
  384.     } else {
  385.     savecmt = NULL;
  386.     flushcomments(&curcomments, -1, -1);
  387.     }
  388.     curcomments = comments;
  389.     curserial = serialcount = 1;
  390.     gettok();
  391.     if (!wexpecttok(TOK_IDENT))
  392.     skiptotoken(TOK_IDENT);
  393.     if (curtokmeaning && curtokmeaning->ctx == curctx &&
  394.         curtokmeaning->kind == MK_FUNCTION) {
  395.         func = curtokmeaning;
  396.         if (!func->isforward || func->val.i)
  397.             warning(format_s("Redeclaration of function %s [270]", func->name));
  398.     skiptotoken(TOK_SEMI);
  399.         movetoend(func);
  400.         pushctx(func);
  401.         type = func->type;
  402.     } else {
  403.         func = addmeaning(curtoksym, MK_FUNCTION);
  404.         gettok();
  405.         func->val.i = 0;
  406.         pushctx(func);
  407.         func->type = type = p_funcdecl(&isfunc, 0);
  408.         func->isfunction = isfunc;
  409.     func->namedfile = isinline;
  410.         type->meaning = func;
  411.     }
  412.     wneedtok(TOK_SEMI);
  413.     if (initializeattr) {
  414.     sl = strlist_append(&initialcalls, format_s("%s()", func->name));
  415.     sl->value = 1;
  416.     }
  417.     if (curtok == TOK_IDENT && !strcmp(curtokbuf, "C")) {
  418.     gettok();
  419.     wneedtok(TOK_SEMI);
  420.     }
  421.     if (blockkind == TOK_IMPORT) {
  422.     strlist_empty(&curcomments);
  423.     if (curtok == TOK_IDENT &&
  424.         (!strcicmp(curtokbuf, "FORWARD") ||
  425.          strlist_cifind(externwords, curtokbuf))) {
  426.         gettok();
  427.         while (curtok == TOK_IDENT)
  428.         gettok();
  429.         wneedtok(TOK_SEMI);
  430.     }
  431.         /* do nothing more */
  432.     } else if (blockkind == TOK_EXPORT) {
  433.         func->isforward = 1;
  434.     scanfwdparams(func);
  435.     flushcomments(NULL, -1, -1);
  436.         forward_decl(func, 1);
  437.     } else {
  438.     checkkeyword(TOK_INTERRUPT);
  439.     checkkeyword(TOK_INLINE);
  440.         if (curtok == TOK_INTERRUPT) {
  441.             note("Ignoring INTERRUPT keyword [258]");
  442.             gettok();
  443.             wneedtok(TOK_SEMI);
  444.         }
  445.         if (curtok == TOK_IDENT && !strcicmp(curtokbuf, "FORWARD")) {
  446.             func->isforward = 1;
  447.         scanfwdparams(func);
  448.             gettok();
  449.             if (func->ctx->kind != MK_FUNCTION) {
  450.                 outsection(minorspace);
  451.         flushcomments(NULL, -1, -1);
  452.                 forward_decl(func, 0);
  453.                 outsection(minorspace);
  454.             }
  455.         } else if (curtok == TOK_IDENT &&
  456.            (strlist_cifind(externwords, curtokbuf) ||
  457.             strlist_cifind(cexternwords, curtokbuf))) {
  458.             if (*externalias && my_strchr(externalias, '%')) {
  459.                 strchange(&func->name, format_s(externalias, func->name));
  460.             } else if (strlist_cifind(cexternwords, curtokbuf)) {
  461.         if (func->name[0] == '_')
  462.             strchange(&func->name, func->name + 1);
  463.         if (func->name[strlen(func->name)-1] == '_')
  464.             func->name[strlen(func->name)-1] = 0;
  465.         }
  466.         func->isforward = 1;    /* for Oregon Software Pascal-2 */
  467.         func->exported = 1;
  468.             gettok();
  469.         while (curtok == TOK_IDENT)
  470.         gettok();
  471.             outsection(minorspace);
  472.         flushcomments(NULL, -1, -1);
  473.         scanfwdparams(func);
  474.             forward_decl(func, 1);
  475.             outsection(minorspace);
  476.     } else if (curtok == TOK_IDENT) {
  477.         wexpecttok(TOK_BEGIN);   /* print warning */
  478.         gettok();
  479.             outsection(minorspace);
  480.         flushcomments(NULL, -1, -1);
  481.         scanfwdparams(func);
  482.             forward_decl(func, 1);
  483.             outsection(minorspace);
  484.         } else {
  485.             if (func->ctx->kind == MK_FUNCTION)
  486.                 func->ctx->needvarstruct = 1;
  487.         func->comments = curcomments;
  488.         curcomments = NULL;
  489.             p_block(TOK_FUNCTION);
  490.             echoprocname(func);
  491.         changecomments(curcomments, -1, curserial, -1, 10000);
  492.             sp = p_body();
  493.             func->ctx->needvarstruct = 0;
  494.             func->val.i = (long)sp;
  495.         strlist_mix(&func->comments, curcomments);
  496.         curcomments = NULL;
  497.             if (func->ctx->kind != MK_FUNCTION || !collectnest) {
  498.                 out_function(func);    /* output top-level procedures immediately */
  499.             }                          /*  (sub-procedures are output later) */
  500.         }
  501.         if (!wneedtok(TOK_SEMI))
  502.         skippasttoken(TOK_SEMI);
  503.     }
  504.     strlist_mix(&curcomments, savecmt);
  505.     popctx();
  506. }
  507.  
  508.  
  509.  
  510. Static void out_include(name, quoted)
  511. char *name;
  512. int quoted;
  513. {
  514.     if (quoted)
  515.         output(format_s("#include \"%s\"\n", name));
  516.     else
  517.         output(format_s("#include <%s>\n", name));
  518. }
  519.  
  520.  
  521. Static void cleanheadername(dest, name)
  522. char *dest, *name;
  523. {
  524.     char *cp;
  525.     int len;
  526.  
  527.     if (*name == '<' || *name == '"')
  528.     name++;
  529.     cp = my_strrchr(name, '/');
  530.     if (cp)
  531.     cp++;
  532.     else
  533.     cp = name;
  534.     strcpy(dest, cp);
  535.     len = strlen(dest);
  536.     if (dest[len-1] == '>' || dest[len-1] == '"')
  537.     dest[len-1] = 0;
  538. }
  539.  
  540.  
  541.  
  542.  
  543. Static int tryimport(sym, fname, ext, need)
  544. Symbol *sym;
  545. char *fname, *ext;
  546. int need;
  547. {
  548.     int found = 0;
  549.     Meaning *savectx, *savectxlast;
  550.  
  551.     savectx = curctx;
  552.     savectxlast = curctxlast;
  553.     curctx = nullctx;
  554.     curctxlast = curctx->cbase;
  555.     while (curctxlast && curctxlast->cnext)
  556.         curctxlast = curctxlast->cnext;
  557.     if (p_search(fname, ext, need)) {
  558.         curtokmeaning = sym->mbase;
  559.         while (curtokmeaning && !curtokmeaning->isactive)
  560.             curtokmeaning = curtokmeaning->snext;
  561.         if (curtokmeaning)
  562.             found = 1;
  563.     }
  564.     curctx = savectx;
  565.     curctxlast = savectxlast;
  566.     return found;
  567. }
  568.  
  569.  
  570.  
  571. Static void p_import(inheader)
  572. int inheader;
  573. {
  574.     Strlist *sl;
  575.     Symbol *sym;
  576.     char *name;
  577.     int found, isfrom = (curtok == TOK_FROM);
  578.  
  579.     outsection(minorspace);
  580.     do {
  581.         gettok();
  582.         if (!wexpecttok(TOK_IDENT)) {
  583.         skiptotoken(TOK_SEMI);
  584.         break;
  585.     }
  586.         sym = curtoksym;
  587.         if (curtokmeaning && curtokmeaning->kind == MK_MODULE) {
  588.             found = 1;
  589.     } else if (strlist_cifind(permimports, sym->name)) {
  590.             found = 2;   /* built-in module, there already! */
  591.         } else {
  592.             found = 0;
  593.             sl = strlist_cifind(importfrom, sym->name);
  594.             name = (sl) ? format_none((char *)sl->value) : NULL;
  595.             if (name) {
  596.                 if (tryimport(sym, name, "pas", 1))
  597.                     found = 1;
  598.             } else {
  599.                 for (sl = importdirs; sl && !found; sl = sl->next) {
  600.                     if (tryimport(sym, format_s(sl->s, curtokcase), NULL, 0))
  601.                         found = 1;
  602.                 }
  603.             }
  604.         }
  605.         if (found == 1) {
  606.             if (!inheader) {
  607.                 sl = strlist_cifind(includefrom, curtokmeaning->name);
  608.                 name = (sl) ? (char *)sl->value :
  609.             format_ss(*headerfnfmt2 ? headerfnfmt2 : headerfnfmt,
  610.                   infname, curtokmeaning->name);
  611.                 if (name && !strlist_find(includedfiles, name)) {
  612.                     strlist_insert(&includedfiles, name);
  613.                     if (*name_HSYMBOL)
  614.                         output(format_s("#ifndef %s\n", format_s(name_HSYMBOL, sym->name)));
  615.                     if (*name == '"' || *name == '<')
  616.                         output(format_s("#include %s\n", name));
  617.                     else
  618.                         out_include(name, quoteincludes);
  619.                     if (*name_HSYMBOL)
  620.                         output("#endif\n");
  621.                     outsection(minorspace);
  622.                 }
  623.             }
  624.             import_ctx(curtokmeaning);
  625.     } else if (curtokmeaning) {
  626.         /* Modula-2, importing a single ident */
  627.         /* Ignored for now, since we always import whole modules */
  628.         } else if (found == 0) {
  629.             warning(format_s("Could not find module %s [271]", sym->name));
  630.             if (!inheader) {
  631.                 out_include(format_ss(*headerfnfmt2?headerfnfmt2:headerfnfmt,
  632.                       sym->name, sym->name),
  633.                 quoteincludes);
  634.             }
  635.         }
  636.         gettok();
  637.     } while (curtok == TOK_COMMA);
  638.     if (isfrom) {
  639.     checkkeyword(TOK_IMPORT);
  640.     if (wneedtok(TOK_IMPORT)) {
  641.         do {
  642.         gettok();
  643.         if (curtok == TOK_IDENT)
  644.             gettok();
  645.         } while (curtok == TOK_COMMA);
  646.     }
  647.     }
  648.     if (!wneedtok(TOK_SEMI))
  649.     skippasttoken(TOK_SEMI);
  650.     outsection(minorspace);
  651. }
  652.  
  653.  
  654.  
  655.  
  656. void do_include(blkind)
  657. Token blkind;
  658. {
  659.     FILE *oldfile = outf;
  660.     int savelnum = outf_lnum;
  661.     char fname[256];
  662.  
  663.     outsection(majorspace);
  664.     strcpy(fname, curtokbuf);
  665.     removesuffix(fname);
  666.     strcat(fname, ".c");
  667.     if (!strcmp(fname, codefname)) {
  668.         warning("Include file name conflict! [272]");
  669.         badinclude();
  670.         return;
  671.     }
  672.     saveoldfile(fname);
  673.     outf = fopen(fname, "w");
  674.     if (!outf) {
  675.         outf = oldfile;
  676.         perror(fname);
  677.         badinclude();
  678.         return;
  679.     }
  680.     outf_lnum = 1;
  681.     output(format_ss("\n/* Include file %s from %s */\n\n", fname, codefname));
  682.     if (blkind == TOK_END)
  683.         gettok();
  684.     else
  685.         curtok = blkind;
  686.     p_block(blockkind);
  687.     output("\n\n/* End. */\n\n");
  688.     fclose(outf);
  689.     outf = oldfile;
  690.     outf_lnum = savelnum;
  691.     if (curtok != TOK_EOF) {
  692.         warning("Junk at end of include file ignored [273]");
  693.     }
  694.     outsection(majorspace);
  695.     if (*includefnfmt)
  696.     out_include(format_s(includefnfmt, fname), 1);
  697.     else
  698.     out_include(fname, 1);
  699.     outsection(majorspace);
  700.     pop_input();
  701.     getline();
  702.     gettok();
  703. }
  704.  
  705.  
  706.  
  707.  
  708. /* blockkind is one of:
  709.        TOK_PROGRAM:     Global declarations of a program
  710.        TOK_FUNCTION:    Declarations local to a procedure or function
  711.        TOK_IMPORT:      Import text read from a module
  712.        TOK_EXPORT:      Export section of a module
  713.        TOK_IMPLEMENT:   Implementation section of a module
  714.        TOK_END:         None of the above
  715. */
  716.  
  717. void p_block(blkind)
  718. Token blkind;
  719. {
  720.     Token saveblockkind = blockkind;
  721.     Token lastblockkind = TOK_END;
  722.  
  723.     blockkind = blkind;
  724.     for (;;) {
  725.     while (curtok == TOK_INTFONLY) {
  726.         include_as_import();
  727.         gettok();
  728.     }
  729.         if (curtok == TOK_CONST || curtok == TOK_TYPE ||
  730.         curtok == TOK_VAR || curtok == TOK_VALUE) {
  731.             while (curtok == TOK_CONST || curtok == TOK_TYPE ||
  732.            curtok == TOK_VAR || curtok == TOK_VALUE) {
  733.                 lastblockkind = curtok;
  734.                 switch (curtok) {
  735.  
  736.                     case TOK_CONST:
  737.                         p_constdecl();
  738.                         break;
  739.  
  740.                     case TOK_TYPE:
  741.                         p_typedecl();
  742.                         break;
  743.  
  744.                     case TOK_VAR:
  745.                         p_vardecl();
  746.                         break;
  747.  
  748.             case TOK_VALUE:
  749.             p_valuedecl();
  750.             break;
  751.  
  752.             default:
  753.             break;
  754.                 }
  755.             }
  756.             if ((blkind == TOK_PROGRAM ||
  757.                  blkind == TOK_EXPORT ||
  758.                  blkind == TOK_IMPLEMENT) &&
  759.                 (curtok != TOK_BEGIN || !mainlocals)) {
  760.                 outsection(majorspace);
  761.                 if (declarevars(curctx, 0))
  762.                     outsection(majorspace);
  763.             }
  764.         } else {
  765.         checkmodulewords();
  766.         checkkeyword(TOK_SEGMENT);
  767.         if (curtok == TOK_SEGMENT) {
  768.         note("SEGMENT or OVERLAY keyword ignored [259]");
  769.         gettok();
  770.         }
  771.         p_attributes();
  772.             switch (curtok) {
  773.  
  774.                 case TOK_LABEL:
  775.                     p_labeldecl();
  776.                     break;
  777.  
  778.                 case TOK_IMPORT:
  779.                 case TOK_FROM:
  780.                     p_import(0);
  781.                     break;
  782.  
  783.         case TOK_EXPORT:
  784.             do {
  785.             gettok();
  786.             checkkeyword(TOK_QUALIFIED);
  787.             if (curtok == TOK_QUALIFIED)
  788.                 gettok();
  789.             wneedtok(TOK_IDENT);
  790.             } while (curtok == TOK_COMMA);
  791.             if (!wneedtok(TOK_SEMI))
  792.             skippasttoken(TOK_SEMI);
  793.             break;
  794.  
  795.                 case TOK_MODULE:
  796.             p_nested_module();
  797.                     break;
  798.  
  799.                 case TOK_PROCEDURE:
  800.                     p_function(0);
  801.                     break;
  802.  
  803.                 case TOK_FUNCTION:
  804.                     p_function(1);
  805.                     break;
  806.  
  807.                 case TOK_INCLUDE:
  808.                     if (blockkind == TOK_PROGRAM ||
  809.                         blockkind == TOK_IMPLEMENT ||
  810.             (blockkind == TOK_FUNCTION && !collectnest)) {
  811.                         do_include(lastblockkind);
  812.                     } else {
  813.                         badinclude();
  814.                     }
  815.                     break;
  816.  
  817.                 default:
  818.             if (curtok == TOK_BEGIN && blockkind == TOK_IMPORT) {
  819.             warning("BEGIN encountered in interface text [274]");
  820.             skipparens();
  821.             if (curtok == TOK_SEMI)
  822.                 gettok();
  823.             break;
  824.             }
  825.                     blockkind = saveblockkind;
  826.                     return;
  827.             }
  828.             lastblockkind = TOK_END;
  829.         }
  830.     }
  831. }
  832.  
  833.  
  834.  
  835.  
  836. Static void skipunitheader()
  837. {
  838.     if (curtok == TOK_LPAR || curtok == TOK_LBR) {
  839.     skipparens();
  840.     }
  841. }
  842.  
  843.  
  844. Static void skiptomodule()
  845. {
  846.     skipping_module++;
  847.     while (curtok != TOK_MODULE) {
  848.         if (curtok == TOK_END) {
  849.             gettok();
  850.             if (curtok == TOK_DOT)
  851.                 break;
  852.         } else
  853.             gettok();
  854.     }
  855.     skipping_module--;
  856. }
  857.  
  858.  
  859.  
  860. Static void p_moduleinit(mod)
  861. Meaning *mod;
  862. {
  863.     Stmt *sp;
  864.     Strlist *sl;
  865.  
  866.     if (curtok != TOK_BEGIN && curtok != TOK_END) {
  867.     wexpecttok(TOK_END);
  868.     skiptotoken2(TOK_BEGIN, TOK_END);
  869.     }
  870.     if (curtok == TOK_BEGIN || initialcalls) {
  871.     echoprocname(mod);
  872.     sp = p_body();
  873.     strlist_mix(&mod->comments, curcomments);
  874.     curcomments = NULL;
  875.     if (ansiC != 0)
  876.         output("void ");
  877.     output(format_s(name_UNITINIT, mod->name));
  878.     if (void_args)
  879.         output("(void)\n");
  880.     else
  881.         output("()\n");
  882.     outcontext = mod;
  883.     out_block(sp, BR_FUNCTION, 10000);
  884.     free_stmt(sp);
  885.     /* The following must come after out_block! */
  886.     sl = strlist_append(&initialcalls,
  887.                 format_s("%s()",
  888.                      format_s(name_UNITINIT, mod->name)));
  889.     sl->value = 1;
  890.     } else
  891.     wneedtok(TOK_END);
  892. }
  893.  
  894.  
  895.  
  896. Static void p_nested_module()
  897. {
  898.     Meaning *mp;
  899.  
  900.     if (!modula2) {
  901.     note("Ignoring nested module [260]");
  902.     p_module(1, 0);
  903.     return;
  904.     }
  905.     note("Nested modules not fully supported [261]");
  906.     checkmodulewords();
  907.     wneedtok(TOK_MODULE);
  908.     wexpecttok(TOK_IDENT);
  909.     mp = addmeaning(curtoksym, MK_MODULE);
  910.     mp->anyvarflag = 0;
  911.     gettok();
  912.     skipunitheader();
  913.     wneedtok(TOK_SEMI);
  914.     p_block(TOK_IMPLEMENT);
  915.     p_moduleinit(mp);
  916.     if (curtok == TOK_IDENT)
  917.     gettok();
  918.     wneedtok(TOK_SEMI);
  919. }
  920.  
  921.  
  922.  
  923. Static int p_module(ignoreit, isdefn)
  924. int ignoreit;
  925. int isdefn;    /* Modula-2: 0=local module, 1=DEFINITION, 2=IMPLEMENTATION */
  926. {
  927.     Meaning *mod, *mp;
  928.     Strlist *sl;
  929.     int kind;
  930.     char *cp;
  931.  
  932.     checkmodulewords();
  933.     wneedtok(TOK_MODULE);
  934.     wexpecttok(TOK_IDENT);
  935.     if (curtokmeaning && curtokmeaning->kind == MK_MODULE && isdefn == 2) {
  936.     mod = curtokmeaning;
  937.     import_ctx(mod);
  938.     for (mp = mod->cbase; mp; mp = mp->cnext)
  939.         if (mp->kind == MK_FUNCTION)
  940.         mp->isforward = 1;
  941.     } else {
  942.     mod = addmeaning(curtoksym, MK_MODULE);
  943.     }
  944.     mod->anyvarflag = 0;
  945.     pushctx(mod);
  946.     gettok();
  947.     skipunitheader();
  948.     wneedtok(TOK_SEMI);
  949.     if (ignoreit || 
  950.         (requested_module && strcicmp(requested_module, mod->name))) {
  951.         if (!quietmode)
  952.         if (outf == stdout)
  953.         fprintf(stderr, "Skipping over module \"%s\"\n", mod->name);
  954.         else
  955.         printf("Skipping over module \"%s\"\n", mod->name);
  956.     checkmodulewords();
  957.         while (curtok == TOK_IMPORT || curtok == TOK_FROM)
  958.             p_import(1);
  959.     checkmodulewords();
  960.     if (curtok == TOK_EXPORT)
  961.         gettok();
  962.         strlist_empty(&curcomments);
  963.         p_block(TOK_IMPORT);
  964.         setup_module(mod->sym->name, 0);
  965.     checkmodulewords();
  966.         if (curtok == TOK_IMPLEMENT) {
  967.             skiptomodule();
  968.         } else {
  969.             if (!wneedtok(TOK_END))
  970.         skippasttoken(TOK_END);
  971.             if (curtok == TOK_SEMI)
  972.                 gettok();
  973.         }
  974.         popctx();
  975.         strlist_empty(&curcomments);
  976.         return 0;
  977.     }
  978.     found_module = 1;
  979.     if (isdefn != 2) {
  980.     if (!*hdrfname) {
  981.         sl = strlist_cifind(includefrom, mod->name);
  982.         if (sl)
  983.         cleanheadername(hdrfname, (char *)sl->value);
  984.         else
  985.         strcpy(hdrfname, format_ss(headerfnfmt, infname, mod->name));
  986.     }
  987.     saveoldfile(hdrfname);
  988.     hdrf = fopen(hdrfname, "w");
  989.     if (!hdrf) {
  990.         perror(hdrfname);
  991.         error("Could not open output file for header");
  992.     }
  993.     outsection(majorspace);
  994.     if (usevextern && my_strchr(name_GSYMBOL, '%'))
  995.         output(format_s("#define %s\n", format_s(name_GSYMBOL, mod->sym->name)));
  996.     out_include(hdrfname, quoteincludes);
  997.     outsection(majorspace);
  998.     select_outfile(hdrf);
  999.     output(format_s("/* Header for module %s, generated by p2c */\n", mod->name));
  1000.     if (*name_HSYMBOL) {
  1001.         cp = format_s(name_HSYMBOL, mod->sym->name);
  1002.         output(format_ss("#ifndef %s\n#define %s\n", cp, cp));
  1003.     }
  1004.     outsection(majorspace);
  1005.     checkmodulewords();
  1006.     while (curtok == TOK_IMPORT || curtok == TOK_FROM)
  1007.         p_import(0);
  1008.     checkmodulewords();
  1009.     if (curtok == TOK_EXPORT)
  1010.         gettok();
  1011.     checkmodulewords();
  1012.     while (curtok == TOK_IMPORT || curtok == TOK_FROM)
  1013.         p_import(0);
  1014.     outsection(majorspace);
  1015.     if (usevextern) {
  1016.         output(format_s("#ifdef %s\n# define vextern\n#else\n",
  1017.                 format_s(name_GSYMBOL, mod->sym->name)));
  1018.         output("# define vextern extern\n#endif\n");
  1019.     }
  1020.     checkmodulewords();
  1021.     p_block(TOK_EXPORT);
  1022.     setup_module(mod->sym->name, 1);
  1023.     outsection(majorspace);
  1024.     if (usevextern)
  1025.         output("#undef vextern\n");
  1026.     outsection(minorspace);
  1027.     if (*name_HSYMBOL)
  1028.         output(format_s("#endif /*%s*/\n", format_s(name_HSYMBOL, mod->sym->name)));
  1029.     output("\n/* End. */\n\n");
  1030.     select_outfile(codef);
  1031.     fclose(hdrf);
  1032.     *hdrfname = 0;
  1033.     redeclarevars(mod);
  1034.     declarevars(mod, 0);
  1035.     }
  1036.     checkmodulewords();
  1037.     if (curtok != TOK_END) {
  1038.     if (!modula2 && !implementationmodules)
  1039.         wneedtok(TOK_IMPLEMENT);
  1040.     import_ctx(mod);
  1041.         p_block(TOK_IMPLEMENT);
  1042.     flushcomments(NULL, -1, -1);
  1043.     p_moduleinit(mod);
  1044.         kind = 1;
  1045.     } else {
  1046.         kind = 0;
  1047.         if (!wneedtok(TOK_END))
  1048.         skippasttoken(TOK_END);
  1049.     }
  1050.     if (curtok == TOK_IDENT)
  1051.     gettok();
  1052.     if (curtok == TOK_SEMI)
  1053.         gettok();
  1054.     popctx();
  1055.     return kind;
  1056. }
  1057.  
  1058.  
  1059.  
  1060.  
  1061. int p_search(fname, ext, need)
  1062. char *fname, *ext;
  1063. int need;
  1064. {
  1065.     char infnbuf[300];
  1066.     FILE *fp;
  1067.     Meaning *mod;
  1068.     int savesysprog, savecopysource;
  1069.     int outerimportmark, importmark, mypermflag;
  1070.  
  1071.     strcpy(infnbuf, fname);
  1072.     fixfname(infnbuf, ext);
  1073.     fp = fopen(infnbuf, "r");
  1074.     if (!fp) {
  1075.         if (need)
  1076.             perror(infnbuf);
  1077.     if (logf)
  1078.         fprintf(logf, "(Unable to open search file \"%s\")\n", infnbuf);
  1079.         return 0;
  1080.     }
  1081.     flushcomments(NULL, -1, -1);
  1082.     ignore_directives++;
  1083.     savesysprog = sysprog_flag;
  1084.     sysprog_flag |= 3;
  1085.     savecopysource = copysource;
  1086.     copysource = 0;
  1087.     outerimportmark = numimports;   /*obsolete*/
  1088.     importmark = push_imports();
  1089.     clearprogress();
  1090.     push_input_file(fp, infnbuf, 0);
  1091.     do {
  1092.     strlist_empty(&curcomments);
  1093.     checkmodulewords();
  1094.     permflag = 0;
  1095.     if (curtok == TOK_DEFINITION) {
  1096.         gettok();
  1097.         checkmodulewords();
  1098.     } else if (curtok == TOK_IMPLEMENT && modula2) {
  1099.         gettok();
  1100.         checkmodulewords();
  1101.         warning("IMPLEMENTATION module in search text! [275]");
  1102.     }
  1103.         if (!wneedtok(TOK_MODULE))
  1104.         break;
  1105.         if (!wexpecttok(TOK_IDENT))
  1106.         break;
  1107.         mod = addmeaning(curtoksym, MK_MODULE);
  1108.         mod->anyvarflag = 0;
  1109.         if (!quietmode && !showprogress)
  1110.         if (outf == stdout)
  1111.         fprintf(stderr, "Reading import text for \"%s\"\n", mod->name);
  1112.         else
  1113.         printf("Reading import text for \"%s\"\n", mod->name);
  1114.     if (verbose)
  1115.         fprintf(logf, "%s, %d/%d: Reading import text for \"%s\"\n",
  1116.             infname, inf_lnum, outf_lnum, mod->name);
  1117.         pushctx(mod);
  1118.         gettok();
  1119.         skipunitheader();
  1120.         wneedtok(TOK_SEMI);
  1121.     mypermflag = permflag;
  1122.         if (debug>0) printf("Found module %s\n", mod->name);
  1123.     checkmodulewords();
  1124.         while (curtok == TOK_IMPORT || curtok == TOK_FROM)
  1125.             p_import(1);
  1126.     checkmodulewords();
  1127.     if (curtok == TOK_EXPORT)
  1128.         gettok();
  1129.         strlist_empty(&curcomments);
  1130.         p_block(TOK_IMPORT);
  1131.         setup_module(mod->sym->name, 0);
  1132.     if (mypermflag) {
  1133.         strlist_add(&permimports, mod->sym->name)->value = (long)mod;
  1134.         perm_import(mod);
  1135.     }
  1136.     checkmodulewords();
  1137.     if (curtok == TOK_END) {
  1138.         gettok();
  1139.         if (curtok == TOK_SEMI)
  1140.         gettok();
  1141.     } else {
  1142.         wexpecttok(TOK_IMPLEMENT);
  1143.         if (importall) {
  1144.         skiptomodule();
  1145.             }
  1146.         }
  1147.         popctx();
  1148.     } while (curtok == TOK_MODULE);
  1149.     pop_imports(importmark);
  1150.     unimport(outerimportmark);
  1151.     sysprog_flag = savesysprog;
  1152.     copysource = savecopysource;
  1153.     ignore_directives--;
  1154.     pop_input();
  1155.     strlist_empty(&curcomments);
  1156.     clearprogress();
  1157.     return 1;
  1158. }
  1159.  
  1160.  
  1161.  
  1162.  
  1163. void p_program()
  1164. {
  1165.     Meaning *prog;
  1166.     Stmt *sp;
  1167.     int nummods, isdefn = 0;
  1168.  
  1169.     flushcomments(NULL, -1, -1);
  1170.     output(format_s("\n#include %s\n", p2c_h_name));
  1171.     outsection(majorspace);
  1172.     p_attributes();
  1173.     ignore_attributes();
  1174.     checkmodulewords();
  1175.     if (modula2) {
  1176.     if (curtok == TOK_MODULE) {
  1177.         curtok = TOK_PROGRAM;
  1178.     } else {
  1179.         if (curtok == TOK_DEFINITION) {
  1180.         isdefn = 1;
  1181.         gettok();
  1182.         checkmodulewords();
  1183.         } else if (curtok == TOK_IMPLEMENT) {
  1184.         isdefn = 2;
  1185.         gettok();
  1186.         checkmodulewords();
  1187.         }
  1188.     }
  1189.     }
  1190.     switch (curtok) {
  1191.  
  1192.         case TOK_MODULE:
  1193.         if (implementationmodules)
  1194.         isdefn = 2;
  1195.             nummods = 0;
  1196.             while (curtok == TOK_MODULE) {
  1197.                 if (p_module(0, isdefn)) {
  1198.                     nummods++;
  1199.                     if (nummods == 2 && !requested_module)
  1200.                         warning("Multiple modules in one source file may not work correctly [276]");
  1201.                 }
  1202.             }
  1203.         wneedtok(TOK_DOT);
  1204.             break;
  1205.  
  1206.         default:
  1207.             if (curtok == TOK_PROGRAM) {
  1208.                 gettok();
  1209.                 if (!wexpecttok(TOK_IDENT))
  1210.             skiptotoken(TOK_IDENT);
  1211.                 prog = addmeaning(curtoksym, MK_MODULE);
  1212.                 gettok();
  1213.                 if (curtok == TOK_LPAR) {
  1214.                     while (curtok != TOK_RPAR) {
  1215.                         if (curtok == TOK_IDENT &&
  1216.                             strcicmp(curtokbuf, "INPUT") &&
  1217.                             strcicmp(curtokbuf, "OUTPUT") &&
  1218.                 strcicmp(curtokbuf, "KEYBOARD") &&
  1219.                 strcicmp(curtokbuf, "LISTING")) {
  1220.                 if (literalfilesflag == 2) {
  1221.                 strlist_add(&literalfiles, curtokbuf);
  1222.                 } else
  1223.                 note(format_s("Unexpected name \"%s\" in program header [262]",
  1224.                           curtokcase));
  1225.                         }
  1226.                         gettok();
  1227.                     }
  1228.                     gettok();
  1229.                 }
  1230.         if (curtok == TOK_LBR)
  1231.             skipparens();
  1232.                 wneedtok(TOK_SEMI);
  1233.             } else {
  1234.                 prog = addmeaning(findsymbol("program"), MK_MODULE);
  1235.             }
  1236.             prog->anyvarflag = 1;
  1237.             if (requested_module && strcicmp(requested_module, prog->name) &&
  1238.                                     strcicmp(requested_module, "program")) {
  1239.                 for (;;) {
  1240.                     skiptomodule();
  1241.                     if (curtok == TOK_DOT)
  1242.                         break;
  1243.                      (void)p_module(0, 2);
  1244.                 }
  1245.         gettok();
  1246.                 break;
  1247.             }
  1248.             pushctx(prog);
  1249.             p_block(TOK_PROGRAM);
  1250.             echoprocname(prog);
  1251.         flushcomments(NULL, -1, -1);
  1252.         if (curtok != TOK_EOF) {
  1253.         sp = p_body();
  1254.         strlist_mix(&prog->comments, curcomments);
  1255.         curcomments = NULL;
  1256.         if (fullprototyping > 0) {
  1257.             output(format_s("main(int argc, %s *argv[])", charname));
  1258.         } else {
  1259.             output("main(argc, argv)\n");
  1260.             singleindent(argindent);
  1261.             output("int argc;\n");
  1262.             singleindent(argindent);
  1263.             output(format_s("%s *argv[];\n", charname));
  1264.         }
  1265.         outcontext = prog;
  1266.         out_block(sp, BR_FUNCTION, 10000);
  1267.         free_stmt(sp);
  1268.         popctx();
  1269.         if (curtok == TOK_SEMI)
  1270.             gettok();
  1271.         else 
  1272.             wneedtok(TOK_DOT);
  1273.         }
  1274.             break;
  1275.  
  1276.     }
  1277.     if (curtok != TOK_EOF) {
  1278.         warning("Junk at end of input file ignored [277]");
  1279.     }
  1280. }
  1281.  
  1282.  
  1283.  
  1284.  
  1285.  
  1286. /* End. */
  1287.  
  1288.  
  1289.