home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Demos / Evatac Software / Preditor 3.0 / Tools / Language Module Builder / Sources / RezParse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-22  |  17.3 KB  |  853 lines  |  [TEXT/TCEd]

  1.  /************************************************************
  2.  
  3.     RezParse.c
  4.     C Source to Preditor 3
  5.  
  6.     Language Module Code for the "Rez" language
  7.  
  8.     © Copyright Evatac Software  1988-1996
  9.     All rights reserved
  10.  
  11. ************************************************************/
  12.  
  13. #include "RezParse.h"
  14. #include <SetupA4.h>
  15. #include <MixedMode.h>
  16. #include <Ctype.h>
  17.  
  18. #ifndef THINKC
  19. #include <A4Stuff.h>
  20. #else
  21. #define SetCurrentA4()    0; RememberA4()
  22. #define SetA4(x)        SetUpA4()
  23. #endif
  24.  
  25. #ifdef powerc
  26. ProcInfoType __procinfo = LanguageUPPInfo;
  27. #endif
  28.  
  29. static languageGlobals            globals;
  30. static ExternalCallbackBlock    *callbacks;
  31.  
  32.  
  33. /*
  34.  * * * *     REZ LANGUAGE ELECTRIC HANDLER       * * * * * *
  35.  */
  36.  
  37. static long _languageConvertToTabs(
  38.     Char    *text,
  39.     long     length,
  40.     long    hardTab
  41.     )
  42. {
  43.     int        tabs   = length / hardTab;
  44.     int        spaces = length % hardTab;
  45.     int        newLen = tabs + spaces;
  46.  
  47.     while (tabs-- > 0)
  48.         *(text++) = 9;
  49.     while (spaces-- > 0)
  50.         *(text++) = ' ';
  51.  
  52.     return(newLen);
  53. }
  54.  
  55. /*
  56.  * _languageHandleElectric
  57.  *
  58.  * We get called only when there is no selection, and one of the
  59.  * 3 electrics is pressed [;{}].
  60.  */
  61. static void _languageHandleElectric(
  62.     Char        ch
  63.     )
  64. {
  65.     long        anchor, end, pos, length;
  66.     long        i;
  67.     long        lineNumber, leading;
  68.     short        spacesPerTab, hardTab;
  69.     Char        text[256], *ptr = text;
  70.     
  71.     extGetSelection(callbacks, &anchor, &end);
  72.  
  73.     lineNumber = extLineFromPosition(callbacks, anchor);
  74.     leading    = extGetLeading(callbacks, lineNumber, &length,
  75.                                 &spacesPerTab, &hardTab);
  76.     
  77.     pos           = anchor;
  78.     anchor        = extLineToPosition(callbacks, lineNumber);
  79.     
  80.     /*
  81.      * Get the indentation of the current line
  82.      */
  83.     
  84.     if (ch == ';') {
  85.                 
  86.         /*
  87.          * Don't expand if we are in the middle a for statement.  Doesn't
  88.          * catch if for is not first word in line, or the (;;) expression
  89.          * spans multiple lines
  90.          */
  91.         
  92.         length = 256 - 4;
  93.         
  94.         extGetText(callbacks, anchor, end, text, &length);
  95.         text[length]   = 0;
  96.         text[length+1] = 0;
  97.         
  98.         while (*ptr == ' ' || *ptr == '\t')
  99.             ptr++;
  100.         ptr[3] = 0;
  101.         
  102.         if (languageCStringCompare(ptr, (Char *) "for") == 0) {
  103.         
  104.             /* 
  105.              * Check to see if we are passed the ')'
  106.              */
  107.             
  108.             ptr += 4;
  109.             
  110.             while (*ptr != 0) {
  111.                 if (*ptr == ')') 
  112.                     break;
  113.                 ptr++;
  114.             }
  115.             
  116.             if (*ptr == 0) {
  117.                 extInsert(callbacks, (Char *) ";", 1);
  118.                 return;
  119.             }
  120.         }
  121.         
  122.         /*
  123.          * Now create the text to insert
  124.          */
  125.         
  126.         text[0] = ';';
  127.         text[1] = '\r';
  128.         
  129.         i = _languageConvertToTabs(text + 2, leading, hardTab); 
  130.         
  131.         extInsert(callbacks, text, i + 2);
  132.     }
  133.     
  134.     else if (ch == '}') {
  135.         
  136.         Int32    x;
  137.         Boolean    sameLine;
  138.         
  139.         /*
  140.          * See if we are on a blank line.  If we are, put the '}' on it,
  141.          * otherwise, insert on a new line
  142.          */
  143.         
  144.         x = extLineEnd(callbacks, lineNumber);
  145.         sameLine = (x - anchor == length);
  146.                     
  147.         text[0] = '}';
  148.         text[1] = 0;
  149.         
  150.         if ((x = extFindMatch(callbacks, text, end)) == -1) {
  151.             extInsert(callbacks, (Char *) "}", 1);
  152.             return;
  153.         }
  154.         
  155.         lineNumber = extLineFromPosition(callbacks, x);
  156.         leading    = extGetLeading(callbacks, lineNumber, &length,
  157.                                     &spacesPerTab, &hardTab);
  158.         
  159.         /*
  160.          * Now create the text to insert
  161.          */
  162.         
  163.         if (sameLine) {
  164.             extSetSelection(callbacks, anchor, pos);
  165.             x = 0;
  166.         }
  167.         else {
  168.             text[0] = '\r';
  169.             x = 1;
  170.         }
  171.         
  172.         i = _languageConvertToTabs(text + x, leading, hardTab); 
  173.         
  174.         text[i+x] = '}';
  175.         
  176.         extInsert(callbacks, text, i + x + 1);
  177.     }
  178.     
  179.     else if (ch == '{') {
  180.     
  181.         /*
  182.          * Create the text to insert
  183.          */
  184.         
  185.         text[0] = '{';
  186.         text[1] = '\r';
  187.         
  188.         i = _languageConvertToTabs(text + 2, leading + spacesPerTab, hardTab); 
  189.         
  190.         extInsert(callbacks, text, i + 2);
  191.     }
  192. }
  193.  
  194. /*
  195.  * * * *     REZ LANGUAGE INDENTING HANDLER       * * * * * *
  196.  */
  197.  
  198. /*
  199.  * _languageHandleIndent
  200.  *
  201.  * Indent the selected lines according to the buffer indentation settings
  202.  */
  203. static void _languageHandleIndent(
  204.     void        *extData
  205.     )
  206. {
  207.     long        anchor, end, pos, length;
  208.     long        lineStart;
  209.     long        i, x, newPos = -1;
  210.     long        lineNumber, endLineNumber, leading;
  211.     short        spacesPerTab, hardTab;
  212.     Char        text[256], ch;
  213.     
  214.     extGetSelection(callbacks, &anchor, &end);
  215.  
  216.     if (anchor > end) {
  217.         pos = anchor; anchor = end; end = pos;   /* Swap */
  218.     }
  219.     
  220.     lineNumber    = extLineFromPosition(callbacks, anchor);
  221.     endLineNumber = extLineFromPosition(callbacks, end);
  222.  
  223.     /*
  224.      * Indent each line in the selection
  225.      */
  226.      
  227.     while (lineNumber <= endLineNumber) {
  228.         
  229.         if (lineNumber <= 1) {
  230.             lineNumber++;
  231.             continue;
  232.         }
  233.         
  234.         leading  = extGetLeading(callbacks, lineNumber, &length,
  235.                                    &spacesPerTab, &hardTab);
  236.     
  237.         lineStart = extLineToPosition(callbacks, lineNumber);
  238.         
  239.         /*
  240.          * Select the leading spaces/tabs
  241.          */
  242.          
  243.         extSetSelection(callbacks, lineStart, lineStart + length);
  244.  
  245.         /*
  246.          * Scan back previous lines for a line that we can relate to
  247.          */
  248.  
  249.         x = 1;
  250.  
  251.         for (;;) {
  252.  
  253.             if (lineNumber - x < 1)
  254.                 break;
  255.  
  256.             leading  = extGetLeading(callbacks, lineNumber - x, &length,
  257.                                        &spacesPerTab, &hardTab);
  258.                                        
  259.             end      = extLineEnd(callbacks, lineNumber - x);
  260.             pos         = extLineToPosition(callbacks, lineNumber - x);
  261.             
  262.             /* Skip Blank lines */
  263.  
  264.             if (length == (end - pos)) {
  265.                 x++;
  266.                 continue;
  267.                }
  268.             
  269.             i = pos + length;
  270.             
  271.             /*
  272.              * Indent right if line contains a left bracket
  273.              */
  274.             
  275.             extScanContents(callbacks, i);
  276.             
  277.             while (i++ < end && extNextScanCharacter(callbacks, &ch)) {
  278.                 
  279.                 if (ch == '{') {
  280.                     leading += spacesPerTab;
  281.                     break;
  282.                 }
  283.             }
  284.             
  285.             extDoneScan(callbacks);
  286.  
  287.         
  288.             /*
  289.               * Indent the line
  290.              */
  291.             
  292.             i = _languageConvertToTabs(text, leading, hardTab); 
  293.         
  294.             extInsert(callbacks, text, i);
  295.             
  296.             if (newPos == -1)
  297.                 newPos = lineStart + i;
  298.             break;
  299.         }
  300.         
  301.         lineNumber++;
  302.     }
  303.  
  304.     if (newPos >= 0)
  305.         extSetSelection(callbacks, newPos, newPos);
  306. }
  307.  
  308. /*
  309.  * * * *     REZ LANGUAGE PARSER       * * * * * *
  310.  */
  311.  
  312. /*
  313.  * _languageBuildString
  314.  *
  315.  * Build up a literal string or literal contant "foo" or 'foo'
  316.  */
  317. static void _languageBuildString(
  318.     languageToken            *token,
  319.     int                        c
  320.     )
  321. {
  322.     Int32    index = 1, size = kTokenStringSize;
  323.     int        origC = c;
  324.     
  325.     token->string[1]     = c;
  326.     token->type = (c == '\"' ? kSymbolStringLiteral : kSymbolCharConstant);
  327.         
  328.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  329.         
  330.         if (index < size)
  331.             token->string[++index] = c;
  332.         
  333.         if (c == origC)
  334.             break;
  335.         
  336.         else if (c == '\\') {
  337.         
  338.             c = languageGetChar(&globals, callbacks);
  339.             
  340.             if (c != -1) {
  341.                 
  342.                 if (index < size)
  343.                     token->string[++index] = c;
  344.             }
  345.         }
  346.     }
  347.     
  348.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  349.     token->string[++index] = 0;
  350. }
  351.  
  352. /*
  353.  * _languageBuildWhiteSpace
  354.  *
  355.  * Build up a directive (i.e. #define, etc)
  356.  */
  357. static void _languageBuildWhiteSpace(
  358.     languageToken             *token,
  359.     int                     c
  360.     )
  361. {
  362.     token->type = kSymbolWhiteSpace;
  363.  
  364.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  365.         
  366.         if (c != ' ' && c != '\t' && c != '\v' && c != '\n' &&
  367.             c != '\r' && c != '\f' && c != '\b') {
  368.     //    if (!isspace(c)) {
  369.             languageUngetChar(&globals, c);
  370.               return;
  371.         }
  372.     }
  373. }
  374.  
  375. /*
  376.  * _languageBuildComment
  377.  *
  378.  */
  379. static void _languageBuildComment(
  380.     languageToken             *token,
  381.     int                     c
  382.     )
  383. {
  384.     Boolean     wasStar;
  385.     
  386.     token->type                 = kSymbolComment;
  387.     globals.startLastComment     = globals.position;
  388.  
  389.     c = languageGetChar(&globals, callbacks);
  390.     
  391.     if (c =='*') {
  392.     
  393.         wasStar = false;
  394.  
  395.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  396.  
  397.             if (c == '*')
  398.                 wasStar = true;
  399.             else if (c != '/' || !wasStar)
  400.                 wasStar = false;
  401.              else
  402.                 break;
  403.         }
  404.     }
  405. }
  406.  
  407. /*
  408.  * _languageBuildNumber
  409.  *
  410.  */
  411. static void _languageBuildNumber(
  412.     languageToken             *token,
  413.     int                     c
  414.     )
  415. {
  416.     Int32            index = 0, size = kTokenStringSize;
  417.     
  418.     token->type = kSymbolIntConstant;
  419.  
  420.     if (c == '$') {
  421.     
  422.         c = languageGetChar(&globals, callbacks);
  423.  
  424.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  425.  
  426.             if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
  427.                 ;
  428.             else
  429.                 break;
  430.         }
  431.     }
  432.     
  433.     else {                                    /* decimal */
  434.  
  435.         if (index < size)
  436.             token->string[++index] = c;
  437.  
  438.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  439.  
  440.             if (c >= '0' && c <= '9') {
  441.                 if (index < size)
  442.                     token->string[++index] = c;
  443.             }
  444.             else
  445.                 break;
  446.         }
  447.  
  448.         if (c == '.') {
  449.             
  450.             token->type = kSymbolFloatConstant;
  451.  
  452.             while ((c = languageGetChar(&globals, callbacks)) != -1) {
  453.             
  454.                 if (c >= '0' && c <= '9')
  455.                     ;
  456.                  else
  457.                     break;
  458.             }
  459.         }
  460.  
  461.         if (c == 'e' || c == 'E') {
  462.         
  463.             token->type = kSymbolFloatConstant;
  464.  
  465.             c = languageGetChar(&globals, callbacks);
  466.  
  467.             if (c == '-' || c == '+')
  468.                 c = languageGetChar(&globals, callbacks);
  469.  
  470.             while (c != -1) {
  471.  
  472.                 if (c >= '0' && c <= '9')
  473.                     ;
  474.                 else
  475.                     break;
  476.  
  477.                 c = languageGetChar(&globals, callbacks);
  478.             }
  479.         }
  480.         
  481.         token->string[0] = index;        /* So string can be used as C or Pascal string */
  482.         token->string[++index] = 0;
  483.     }
  484.  
  485.     if (c != -1)
  486.         languageUngetChar(&globals, c);
  487. }
  488.  
  489. /*
  490.  * _languageBuildInclude
  491.  */
  492. static void _languageBuildInclude(
  493.     languageToken             *token,
  494.     int                     c
  495.     )
  496. {
  497.     Int32            index = 0, size = kTokenStringSize;
  498.  
  499.     languageUngetChar(&globals, c);
  500.     _languageBuildWhiteSpace(token, c);
  501.     
  502.     token->type = kSymbolInclude;
  503.     
  504.     if ((c = languageGetChar(&globals, callbacks)) == '\"' || c == '<') {
  505.     
  506.         while ((c = languageGetChar(&globals, callbacks)) != -1) {
  507.  
  508.             if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'
  509.                 || c >= '0' && c <= '9' || c == '.') {
  510.         
  511.                 if (index < size)
  512.                     token->string[++index] = c;
  513.             }
  514.             else {
  515.                 break;
  516.             }
  517.         }
  518.     }
  519.  
  520.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  521.     token->string[++index] = 0;
  522. }
  523.  
  524. /*
  525.  * _languageBuildWord
  526.  *
  527.  *
  528.  */
  529. static void _languageBuildWord(
  530.     languageToken             *token,
  531.     int                     c
  532.     )
  533. {
  534.     Int32            index = 1, size = kTokenStringSize;
  535.  
  536.     token->type = kSymbolIdentifier;
  537.  
  538.     token->string[1] = c;
  539.     
  540.     while ((c = languageGetChar(&globals, callbacks)) != -1) {
  541.  
  542.         if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'
  543.             || c >= '0' && c <= '9') {
  544.         
  545.             if (index < size)
  546.                 token->string[++index] = c;
  547.         }
  548.         else {
  549.         
  550.             languageUngetChar(&globals, c);
  551.             break;
  552.         }
  553.     }
  554.  
  555.     token->string[0] = index;        /* So string can be used as C or Pascal string */
  556.     token->string[++index] = 0;
  557.     
  558.     /*
  559.      * Since hashing into a large reserved word table takes time, the reserved
  560.      * word table is not loaded for "function" scanning.  We do our own
  561.      * limited keyword check
  562.      */
  563.      
  564.     if (!languageHasTable(&globals)) {
  565.         
  566.         Char        *scan = token->string + 1;
  567.         
  568.         if (languageCStringCompare(scan, (Char *) "type") == 0)
  569.             token->type = kSymbolReservedWord;
  570.         else if (languageCStringCompare(scan, (Char *) "resource") == 0)
  571.             token->type = kSymbolReservedWord;
  572.             
  573.         return;
  574.     }
  575.     
  576.     else if (languageTableLookup((&globals), token->string + 1))
  577.         token->type = kSymbolReservedWord;
  578.     else if (languageCustomTableLookup((&globals), token->string + 1))
  579.         token->type = kSymbolCustomWord;
  580. }
  581.  
  582. /*
  583.  * _languageConcatPStrings
  584.  * 
  585.  * Concatenate two Pascal strings by attaching the second string on
  586.  * the end of the first    string.
  587.  */
  588. static void _languageConcatPStrings(
  589.     Char    *first,
  590.     Char    *second
  591.     )
  592. {
  593.     BlockMove(second + 1, first    + first[0] + 1,    (long) second[0]);
  594.     first[0] +=    second[0];
  595. }
  596.  
  597. /*
  598.  * _languageGetNextToken
  599.  */
  600. static languageToken *_languageGetNextToken(void)
  601. {
  602.     int                     first, second;
  603.     Int16                    previousType;
  604.     languageToken            *token = &globals.token;
  605.    
  606.     previousType            = token->type;
  607.     token->startLocation     = globals.position;
  608.     token->majorType        = -1;
  609.  
  610.     if ((first = languageGetChar(&globals, callbacks)) == -1)
  611.         return(nil);
  612.  
  613.     token->type             = first;
  614.  
  615.     second = languagePeekChar(&globals, callbacks);
  616.     
  617.     if (previousType == kSymbolReservedWord && 
  618.         token->string[1] == '#' && token->string[3] == 'n') {
  619.  
  620.         _languageBuildInclude(token, first);
  621.         first = 0;
  622.     }
  623.  
  624.     switch(first) {
  625.  
  626. /* "strings" */
  627. /* 'character constants' */
  628.  
  629.     case '\"':
  630.     case '\'':
  631.         _languageBuildString(token, first);
  632.         break;
  633.     
  634.     case ';':
  635.         globals.startLastComment = -1;
  636.         break;
  637.         
  638. /* preprocessor directive */
  639.  
  640.     case '#':
  641.         _languageBuildWord(token, first);
  642.         globals.startLastComment = -1;
  643.         break;
  644.  
  645. /* white space */
  646.  
  647.     case ' ': case '\t': case '\v': case '\n': case '\r': case '\f': case '\b':
  648.         _languageBuildWhiteSpace(token, first);
  649.         break;
  650.  
  651.     case '/':
  652.         if (second == '*')
  653.             _languageBuildComment(token, first);
  654.         break;
  655.  
  656. /* ., .*, .NUM */
  657.  
  658.     case '.':
  659.         if (second >= '0' && second <= '9')
  660.             _languageBuildNumber(token, first);
  661.         break;
  662.  
  663. /* the rest */
  664.  
  665.     default:
  666.         if (first >= '0' && first <= '9')
  667.             _languageBuildNumber(token, first);
  668.         else if (first >= 'a' && first <= 'z' || first >= 'A' && first <= 'Z' ||
  669.                  first == '_')
  670.                _languageBuildWord(token, first);
  671.  
  672.         /* Something weird, let the parser decide. */
  673.  
  674.         break;
  675.     }
  676.  
  677.     token->endLocation    = globals.position;
  678.     
  679.     return(token);
  680. }
  681.  
  682. void languageMain(
  683.     ExternalCallbackBlock    *extCallbacks,
  684.     WindowRef                window,
  685.     long                    options,
  686.     void                    *extData
  687.     );
  688.     
  689. /*
  690.  * languageMain
  691.  *
  692.  * This is the main entrypoint to the CODE module of a language module.
  693.  * The following operations are defined:
  694.  *
  695.  *     kLanguageParse        Parse the source file, returning positions of all tokens
  696.  *                        in the file.
  697.  *  kLanguageFunctions    Parse the source file, returning the position of just the
  698.  *                        functions in the source file
  699.  *  kLanguageIncludes    Parse the source file, returning the #include files
  700.  *  kLanguageTemplate    Expand macro -- insert template
  701.  *  kLanguageIndentLine
  702.  *    kLanguageElectric    Handle electric characters (i.e. }, {, ; )
  703.  */
  704. void main(
  705.     ExternalCallbackBlock    *extCallbacks,
  706.     WindowRef                window,
  707.     long                    options,
  708.     void                    *extData
  709.     )
  710. {
  711.     languageToken        *token, saveToken;
  712.     Int16                i, type;
  713.     Boolean                isType;
  714.     long                 saved_a4;
  715.  
  716.     saved_a4 = SetCurrentA4();
  717.  
  718.     languageInit(&globals, extCallbacks, options);
  719.  
  720.     callbacks    = extCallbacks;
  721.  
  722.     if (options == kLanguageTemplate) {
  723.  
  724.         languageDefaultHandler(&globals, callbacks, options, extData);
  725.     } 
  726.     
  727.     else if (options == kLanguageElectric) {
  728.         
  729.         _languageHandleElectric((Char) extData);
  730.     }
  731.     
  732.     else if (options == kLanguageIndent) {
  733.         
  734.         _languageHandleIndent(extData);
  735.     }
  736.     
  737.     else if (options <= kLanguageIncludes) {
  738.         
  739.         /*
  740.          * Now parse the file, returning a series of valid return token types:
  741.          *
  742.          *        kFunction
  743.          *         kKeyword
  744.          *         kComment
  745.          *        kCustomKeyword
  746.          */
  747.             
  748.         while ((token = _languageGetNextToken()) != nil) {
  749.         
  750.             type = token->type;
  751.             
  752.             if (type == kSymbolReservedWord) {
  753.             
  754.                 token->majorType = kKeyword;
  755.                 
  756.                 /*
  757.                  * Check for keyword 'type' or 'resource' 
  758.                  */
  759.                 
  760.                 if (options == kLanguageFunctions &&
  761.                    (token->string[1] == 't' ||
  762.                     token->string[1] == 'r' && token->string[3] == 's')) { 
  763.                 
  764.                     isType = (token->string[1] == 't');
  765.     
  766.                     _languageBuildWhiteSpace(token,
  767.                              languageGetChar(&globals, callbacks));
  768.                     
  769.                     if (languageGetChar(&globals, callbacks) == '\'') {
  770.                         
  771.                         /* Pull out the 'TYPE' info */
  772.                         
  773.                         for (i=1; i<=4; i++)
  774.                             token->string[i] =
  775.                                 languageGetChar(&globals, callbacks);
  776.                         
  777.                         token->string[0] = 4;
  778.                         token->string[5] = 0;
  779.                         
  780.                         /* Skip the matching "'" */
  781.                         
  782.                         languageGetChar(&globals, callbacks);
  783.                         
  784.                         saveToken                  = *token;
  785.                         saveToken.startLocation = globals.position - 5;
  786.                         saveToken.endLocation   = globals.position - 1;
  787.                         
  788.                         /*
  789.                          * Get the resource id for 'resource' definitions
  790.                          */
  791.                          
  792.                         if (!isType) {
  793.         
  794.                             while ((token = _languageGetNextToken()) != nil &&
  795.                                    token->type != kSymbolIntConstant)
  796.                                 ;
  797.                                 
  798.                             saveToken.endLocation = globals.position;
  799.                             
  800.                             /*
  801.                              * Append the resource id to the end of the definition string
  802.                              */
  803.                             
  804.                             if (token != nil) {
  805.                                 
  806.                                 saveToken.string[++(*saveToken.string)] = ' ';
  807.     
  808.                                 _languageConcatPStrings(saveToken.string, token->string);
  809.                                                         
  810.                                 saveToken.string[(*saveToken.string) + 1] = 0;
  811.                             }
  812.                         }
  813.                         
  814.                         saveToken.majorType       = kDefinition;
  815.                         saveToken.commentLocation = globals.startLastComment;
  816.                         extTokenReturn(callbacks, &saveToken);
  817.                     }
  818.                 }
  819.             }
  820.         
  821.             else if (type == kSymbolCustomWord) {
  822.                 token->majorType = kCustomKeyword;
  823.             }
  824.  
  825.             else if (type == kSymbolComment)
  826.                 token->majorType = kComment;
  827.             
  828.             else if (type == kSymbolInclude && options == kLanguageIncludes) {
  829.        
  830.                 token->majorType = kDefinition;
  831.                 
  832.                 extTokenReturn(callbacks, token);
  833.             }
  834.  
  835.             /*
  836.              * Only return a token if it's a interesting token, and
  837.              * if we are doing a full parse
  838.              */
  839.              
  840.             if (token->majorType >= 0 && options == kLanguageParse)
  841.                 extTokenReturn(callbacks, token);
  842.         }
  843.     }
  844.     
  845.     /*
  846.      * Clean up after ourselves
  847.      */
  848.  
  849.     languageDone(&globals, callbacks);
  850.     
  851.     SetA4(saved_a4);
  852. }
  853.