home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / TextEditors&Viewers / Texteditors / WarpA68k09.lha / WarpA68K / source / funcs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-23  |  22.9 KB  |  785 lines

  1. /* -----------------------------------------------------------------------------
  2.  
  3.  ScanLib ©1995 Dietmar Eilert
  4.  
  5.  GoldED syntax parser example library (uses a syntax cache). Dice:
  6.  
  7.  DMAKE
  8.  
  9.  -------------------------------------------------------------------------------
  10.  
  11. */
  12.  
  13. #include "defs.h"
  14.  
  15. /// "Header stuff"
  16.  
  17. // Buffer handles are allocated for each text buffer to keep track of ressources:
  18.  
  19. struct BufferHandle {
  20.  
  21.     struct EditConfig     *bh_EditConfig;            // pointer to text data
  22.     struct GlobalConfig   *bh_GlobalConfig;          // editor configuration
  23.     struct SyntaxChunk    *bh_SyntaxStack;           // parser output
  24.     struct RefreshRequest  bh_RefreshRequest;        // display refresh request
  25. };
  26.  
  27. // known opcodes are described by syntax structures
  28.  
  29. struct Keyword {
  30.  
  31.     UBYTE *Pattern;                                  // known pattern (e.g. "move")
  32.     UWORD  Len;                                      // base length
  33.     UWORD  Level;                                    // syntax level
  34. };
  35.  
  36. #define UPPER(a)    ((a) & 95)                       // simple uppercase conversion
  37. #define EMPTY_STACK ((struct SyntaxChunk *)~0)       // empty stack flag
  38.  
  39. // syntax levels recognized by this parser
  40.  
  41. #define SYNTAX_STANDARD         0
  42. #define SYNTAX_LABELGLOBAL      1
  43. #define SYNTAX_LABELLOCAL       2
  44. #define SYNTAX_BRANCH           3
  45. #define SYNTAX_OPCODE           4
  46. #define SYNTAX_ARGUMENTS        5
  47. #define SYNTAX_COMMENTSHORT     6
  48. #define SYNTAX_COMMENTLONG      7
  49. #define SYNTAX_XDEFXREF         8
  50. #define SYNTAX_DATA             9
  51. #define SYNTAX_ASSEMBLER       10
  52. #define SYNTAX_FORBIDDEN       11
  53.  
  54. ///
  55. /// "Prototype"
  56.  
  57. // library functions
  58.  
  59. Prototype LibCall struct ParserData     *MountScanner(void);
  60. Prototype LibCall ULONG                  StartScanner(__A0 struct GlobalConfig *, __A1 struct EditConfig *, __D0 struct SyntaxChunk *);
  61. Prototype LibCall ULONG                  CloseScanner(__D0 ULONG);
  62. Prototype LibCall void                   FlushScanner(__D0 ULONG);
  63. Prototype LibCall void                   SetupScanner(__A0 struct GlobalConfig  *);
  64. Prototype LibCall struct RefreshRequest *BriefScanner(__D0 ULONG, __A0 struct ScannerNotify *);
  65. Prototype LibCall struct SyntaxChunk    *ParseLine   (__D0 ULONG, __A0 struct LineNode *, __D1 ULONG);
  66. Prototype LibCall void                   UnparseLines(__A0 struct LineNode *, __D0 ULONG);
  67. Prototype LibCall void                   ParseSection(__D0 ULONG, __A0 struct LineNode *, __D1 ULONG);
  68.  
  69. // private functions
  70.  
  71. Prototype struct SyntaxChunk *ParseString(UBYTE *, UWORD, ULONG);
  72. Prototype struct SyntaxChunk *DupStack(struct SyntaxChunk *);
  73. Prototype void                PrepareHash(void);
  74. Prototype UWORD               CheckOpcode(UBYTE *, UWORD, UWORD);
  75. Prototype BOOL                memicmp(UBYTE *, UBYTE *, UWORD);
  76.  
  77. ///
  78. /// "Globals"
  79.  
  80. struct Keyword *Hash[256];
  81.  
  82. struct Keyword Reserved[] = {
  83.  
  84.     //  opcode     opcode_length   syntax_level
  85.  
  86.     {  "ADDSYM",        0,         SYNTAX_ASSEMBLER },
  87.     {  "BASEREG",       0,         SYNTAX_ASSEMBLER },
  88.     {  "BEQ",           0,         SYNTAX_BRANCH    },
  89.     {  "BGE",           0,         SYNTAX_BRANCH    },
  90.     {  "BGT",           0,         SYNTAX_BRANCH    },
  91.     {  "BHI",           0,         SYNTAX_BRANCH    },
  92.     {  "BLE",           0,         SYNTAX_BRANCH    },
  93.     {  "BLM",           0,         SYNTAX_BRANCH    },
  94.     {  "BLS",           0,         SYNTAX_BRANCH    },
  95.     {  "BMI",           0,         SYNTAX_BRANCH    },
  96.     {  "BNE",           0,         SYNTAX_BRANCH    },
  97.     {  "BOPT",          0,         SYNTAX_ASSEMBLER },
  98.     {  "BPL",           0,         SYNTAX_BRANCH    },
  99.     {  "BRA",           0,         SYNTAX_BRANCH    },
  100.     {  "BVC",           0,         SYNTAX_BRANCH    },
  101.     {  "BVS",           0,         SYNTAX_BRANCH    },
  102.     {  "CNOP",          0,         SYNTAX_ASSEMBLER },
  103.     {  "COMMENT",       0,         SYNTAX_ASSEMBLER },
  104.     {  "CSECT",         0,         SYNTAX_ASSEMBLER },
  105.     {  "CSTR",          0,         SYNTAX_ASSEMBLER },
  106.     {  "DBEQ",          0,         SYNTAX_BRANCH    },
  107.     {  "DBGE",          0,         SYNTAX_BRANCH    },
  108.     {  "DBGT",          0,         SYNTAX_BRANCH    },
  109.     {  "DBHI",          0,         SYNTAX_BRANCH    },
  110.     {  "DBLE",          0,         SYNTAX_BRANCH    },
  111.     {  "DBLM",          0,         SYNTAX_BRANCH    },
  112.     {  "DBLS",          0,         SYNTAX_BRANCH    },
  113.     {  "DBMI",          0,         SYNTAX_BRANCH    },
  114.     {  "DBNE",          0,         SYNTAX_BRANCH    },
  115.     {  "DBPL",          0,         SYNTAX_BRANCH    },
  116.     {  "DBVC",          0,         SYNTAX_BRANCH    },
  117.     {  "DBVS",          0,         SYNTAX_BRANCH    },
  118.     {  "DC",            0,         SYNTAX_DATA      },
  119.     {  "DEBUG",         0,         SYNTAX_ASSEMBLER },
  120.     {  "DL",            0,         SYNTAX_DATA      },
  121.     {  "DS",            0,         SYNTAX_DATA      },
  122.     {  "DW",            0,         SYNTAX_DATA      },
  123.     {  "ELSEIF",        0,         SYNTAX_ASSEMBLER },
  124.     {  "END",           0,         SYNTAX_ASSEMBLER },
  125.     {  "END",           0,         SYNTAX_ASSEMBLER },
  126.     {  "ENDC",          0,         SYNTAX_ASSEMBLER },
  127.     {  "ENDM",          0,         SYNTAX_ASSEMBLER },
  128.     {  "ENDR",          0,         SYNTAX_ASSEMBLER },
  129.     {  "EQU",           0,         SYNTAX_ASSEMBLER },
  130.     {  "EQU",           0,         SYNTAX_ASSEMBLER },
  131.     {  "EQUR",          0,         SYNTAX_ASSEMBLER },
  132.     {  "EVEN",          0,         SYNTAX_ASSEMBLER },
  133.     {  "EXEOBJ",        0,         SYNTAX_ASSEMBLER },
  134.     {  "FAIL",          0,         SYNTAX_ASSEMBLER },
  135.     {  "IFC",           0,         SYNTAX_ASSEMBLER },
  136.     {  "IFD",           0,         SYNTAX_ASSEMBLER },
  137.     {  "IFEQ",          0,         SYNTAX_ASSEMBLER },
  138.     {  "IFGE",          0,         SYNTAX_ASSEMBLER },
  139.     {  "IFGT",          0,         SYNTAX_ASSEMBLER },
  140.     {  "IFLE",          0,         SYNTAX_ASSEMBLER },
  141.     {  "IFLT",          0,         SYNTAX_ASSEMBLER },
  142.     {  "IFNC",          0,         SYNTAX_ASSEMBLER },
  143.     {  "IFND",          0,         SYNTAX_ASSEMBLER },
  144.     {  "IFNE",          0,         SYNTAX_ASSEMBLER },
  145.     {  "ILLEGAL",       0,         SYNTAX_FORBIDDEN },
  146.     {  "INCDIR",        0,         SYNTAX_ASSEMBLER },
  147.     {  "INCLUDE",       0,         SYNTAX_ASSEMBLER },
  148.     {  "JMP",           0,         SYNTAX_BRANCH    },
  149.     {  "JSR",           0,         SYNTAX_BRANCH    },
  150.     {  "MACLIB",        0,         SYNTAX_ASSEMBLER },
  151.     {  "MACRO",         0,         SYNTAX_ASSEMBLER },
  152.     {  "MC68000",       0,         SYNTAX_ASSEMBLER },
  153.     {  "MC68010",       0,         SYNTAX_ASSEMBLER },
  154.     {  "MC68020",       0,         SYNTAX_ASSEMBLER },
  155.     {  "MC68030",       0,         SYNTAX_ASSEMBLER },
  156.     {  "MC68040",       0,         SYNTAX_ASSEMBLER },
  157.     {  "MC68060",       0,         SYNTAX_ASSEMBLER },
  158.     {  "MEXIT",         0,         SYNTAX_ASSEMBLER },
  159.     {  "MULTIPASS",     0,         SYNTAX_ASSEMBLER },
  160.     {  "NEWSYNTAX",     0,         SYNTAX_ASSEMBLER },
  161.     {  "OBJFILE",       0,         SYNTAX_ASSEMBLER },
  162.     {  "OFFSET",        0,         SYNTAX_ASSEMBLER },
  163.     {  "OPT",           0,         SYNTAX_ASSEMBLER },
  164.     {  "ORG",           0,         SYNTAX_ASSEMBLER },
  165.     {  "OUTPUT",        0,         SYNTAX_ASSEMBLER },
  166.     {  "OUTPUT",        0,         SYNTAX_ASSEMBLER },
  167.     {  "REPT",          0,         SYNTAX_ASSEMBLER },
  168.     {  "RESET",         0,         SYNTAX_FORBIDDEN },
  169.     {  "RTE",           0,         SYNTAX_FORBIDDEN },
  170.     {  "SECTION",       0,         SYNTAX_ASSEMBLER },
  171.     {  "SEQ",           0,         SYNTAX_BRANCH    },
  172.     {  "SET",           0,         SYNTAX_ASSEMBLER },
  173.     {  "SGE",           0,         SYNTAX_BRANCH    },
  174.     {  "SGT",           0,         SYNTAX_BRANCH    },
  175.     {  "SHI",           0,         SYNTAX_BRANCH    },
  176.     {  "SLE",           0,         SYNTAX_BRANCH    },
  177.     {  "SLM",           0,         SYNTAX_BRANCH    },
  178.     {  "SLS",           0,         SYNTAX_BRANCH    },
  179.     {  "SMI",           0,         SYNTAX_BRANCH    },
  180.     {  "SNE",           0,         SYNTAX_BRANCH    },
  181.     {  "SPL",           0,         SYNTAX_BRANCH    },
  182.     {  "STOP",          0,         SYNTAX_FORBIDDEN },
  183.     {  "STOP",          0,         SYNTAX_FORBIDDEN },
  184.     {  "SVC",           0,         SYNTAX_BRANCH    },
  185.     {  "SVS",           0,         SYNTAX_BRANCH    },
  186.     {  "SYM",           0,         SYNTAX_ASSEMBLER },
  187.     {  "TAS",           0,         SYNTAX_FORBIDDEN },
  188.     {  "TRASHREG",      0,         SYNTAX_ASSEMBLER },
  189.     {  "VERBOSEOPTIM",  0,         SYNTAX_ASSEMBLER },
  190.     {  "XDEF",          0,         SYNTAX_XDEFXREF  },
  191.     {  "XREF",          0,         SYNTAX_XDEFXREF  },
  192.  
  193.     { NULL, 0, 0}
  194. };
  195.  
  196. ///
  197. /// "Library functions"
  198.  
  199. /* ------------------------------- MountScanner --------------------------------
  200.  
  201.  Called by the editor before first usage of a scanner. Return a description of
  202.  our abilities.
  203.  
  204. */
  205.  
  206. LibCall struct ParserData *
  207. MountScanner()
  208. {
  209.     static struct ParserData parserData;
  210.  
  211.     // syntax elements understood by parser
  212.  
  213.     static UBYTE *levelNames[] = {
  214.  
  215.         "Standard text",
  216.         "Label global",
  217.         "Label local",
  218.         "Branches",
  219.         "Opcode",
  220.         "Arguments",
  221.         "Comment - short",
  222.         "Comment - long",
  223.         "xdef/xref",
  224.         "Data",
  225.         "Assembler",
  226.         "Forbidden",
  227.  
  228.         NULL
  229.     };
  230.  
  231.     // color suggestions
  232.  
  233.     static ULONG *levelColors[] = {
  234.  
  235.         MAKE_RGB4(0,  0,   0),
  236.         MAKE_RGB4(15, 15,  0),
  237.         MAKE_RGB4(0,  15, 15),
  238.         MAKE_RGB4(15,  0,  0),
  239.         MAKE_RGB4(0,  15,  0),
  240.         MAKE_RGB4(0,   0, 15),
  241.         MAKE_RGB4(15, 15, 15),
  242.         MAKE_RGB4(15,  0, 15),
  243.         MAKE_RGB4(0,   0,  0),
  244.         MAKE_RGB4(0,   0,  0),
  245.         MAKE_RGB4(0,   0,  0),
  246.         MAKE_RGB4(15, 15, 15),
  247.         MAKE_RGB4(0,  15,  0),
  248.     };
  249.  
  250.     parserData.pd_Release  = SCANLIBVERSION;
  251.     parserData.pd_Version  = 1;
  252.     parserData.pd_Serial   = 0;
  253.     parserData.pd_Info     = "Warp A68K 0.9 ©'95 D.Eilert";
  254.     parserData.pd_Levels   = 12;
  255.     parserData.pd_Names    = levelNames;
  256.     parserData.pd_Colors   = levelColors;
  257.     parserData.pd_Flags    = SCPRF_SYNTAXCACHE | SCPRF_CONTEXT;
  258.     parserData.pd_Reserved = 0;
  259.  
  260.     PrepareHash();
  261.  
  262.     return(&parserData);
  263. }
  264.  
  265.  
  266. /* ------------------------------- StartScanner --------------------------------
  267.  
  268.  Called by the editor after a new text buffer has been created. We allocate a
  269.  buffer to hold text-specific data. The buffer address is returned as handle.
  270.  
  271. */
  272.  
  273. LibCall ULONG
  274. StartScanner(__A0 struct GlobalConfig *globalConfigPtr, __A1 struct EditConfig *editConfigPtr, __D0 struct SyntaxChunk *syntaxStack)
  275. {
  276.     struct BufferHandle *handle;
  277.  
  278.     if (handle = AllocVec(sizeof(struct BufferHandle), MEMF_PUBLIC | MEMF_CLEAR)) {
  279.  
  280.         handle->bh_GlobalConfig = globalConfigPtr;
  281.         handle->bh_EditConfig   = editConfigPtr;
  282.         handle->bh_SyntaxStack  = syntaxStack;
  283.     }
  284.  
  285.     return((ULONG)handle);
  286. }
  287.  
  288.  
  289. /* ------------------------------- CloseScanner --------------------------------
  290.  
  291.  Called by the editor if a text buffer is about to be closed. Deallocate buffer
  292.  specific 'global' data.
  293.  
  294. */
  295.  
  296. LibCall ULONG
  297. CloseScanner(__D0 ULONG scanID)
  298. {
  299.     if (scanID) {
  300.  
  301.         struct BufferHandle *handle = (struct BufferHandle *)scanID;
  302.  
  303.         FreeVec(handle);
  304.     }
  305.  
  306.     return(0);
  307. }
  308.  
  309.  
  310. /* ------------------------------- FlushScanner --------------------------------
  311.  
  312.  Called by the editor in low memory situations: we are supposed to free as much
  313.  memory as possible.
  314.  
  315. */
  316.  
  317. LibCall void
  318. FlushScanner(__D0 ULONG scanID)
  319. {
  320.     struct BufferHandle *handle;
  321.     struct EditConfig   *config;
  322.     struct LineNode     *lineNode;
  323.  
  324.     handle = (struct BufferHandle *)scanID;
  325.     config = handle->bh_EditConfig;
  326.  
  327.     if (lineNode = config->TextNodes)
  328.         UnparseLines(lineNode, config->Lines);
  329. }
  330.  
  331.  
  332. /* ------------------------------- SetupScanner --------------------------------
  333.  
  334.  Called by the editor if the user wants to change the scanner's configuration.
  335.  We do not support user configuration (parserData.pd_Flags: SCPRF_CONFIGWIN flag
  336.  unset).
  337.  
  338. */
  339.  
  340. LibCall void
  341. SetupScanner(__A0 globalConfigPtr)
  342. {
  343.     ;
  344. }
  345.  
  346.  
  347. /* ------------------------------- BriefScanner --------------------------------
  348.  
  349.  Called to notify a context scanner if lines have been added, deleted or
  350.  modified. We aren't a context scanner (parserData.pd_Flags: SCPRF_CONTEXT
  351.  flag unset), so we won't ever have to request additional display requests:
  352.  the editor's built-in refresh of damage regions is sufficient.
  353.  
  354. */
  355.  
  356. LibCall struct RefreshRequest *
  357. BriefScanner(__D0 ULONG scanID, __A0 struct ScannerNotify *notify)
  358. {
  359.     return(NULL);
  360. }
  361.  
  362.  
  363. /* --------------------------------- ParseLine ---------------------------------
  364.  
  365.  Parse a line, build a syntax description
  366.  
  367. */
  368.  
  369. LibCall struct SyntaxChunk *
  370. ParseLine(__D0 ULONG scanID, __A0 struct LineNode *lineNode, __D1 ULONG line)
  371. {
  372.     if (lineNode->Fold)
  373.  
  374.         return(NULL);
  375.  
  376.     else if (lineNode->Len) {
  377.  
  378.         // line not yet parsed ?
  379.  
  380.         if (lineNode->UserData == NULL) {
  381.  
  382.             struct SyntaxChunk *syntaxStack = ParseString(lineNode->Text, lineNode->Len, scanID);
  383.  
  384.             if (syntaxStack == EMPTY_STACK)
  385.                 lineNode->UserData = EMPTY_STACK;
  386.             else
  387.                 lineNode->UserData = DupStack(syntaxStack);
  388.         }
  389.  
  390.         if (lineNode->UserData == EMPTY_STACK)
  391.             return((struct SyntaxChunk *)NULL);
  392.         else
  393.             return((struct SyntaxChunk *)lineNode->UserData);
  394.     }
  395.     else
  396.         return(NULL);
  397. }
  398.  
  399. /* -------------------------------- UnparseLines -------------------------------
  400.  
  401.  Called by the editor if lines are to be deleted. We are supposed to free
  402.  private data attached to the lines.
  403.  
  404. */
  405.  
  406. LibCall void
  407. UnparseLines(__A0  struct LineNode *lineNode, __D0 ULONG lines)
  408. {
  409.     while (lines--) {
  410.  
  411.         // free syntax cache
  412.  
  413.         if (lineNode->UserData) {
  414.  
  415.             if (lineNode->UserData != (APTR)EMPTY_STACK)
  416.                 FreeVec((APTR)lineNode->UserData);
  417.  
  418.             lineNode->UserData = NULL;
  419.         }
  420.  
  421.         // free folded subblock
  422.  
  423.         if (lineNode->Fold)
  424.             UnparseLines(lineNode->Fold->TextNodes, lineNode->Fold->Lines);
  425.  
  426.         ++lineNode;
  427.     }
  428. }
  429.  
  430. /* -------------------------------- ParseSection -------------------------------
  431.  
  432.  Called by the editor if lines are to be displayed. The scanner is encouraged to
  433.  preparse the lines.
  434.  
  435. */
  436.  
  437. LibCall void
  438. ParseSection(__D0 ULONG scanID, __A0  struct LineNode *lineNode, __D1 ULONG lines)
  439. {
  440.     while (lines--) {
  441.  
  442.         // fold headers have to be ignored
  443.  
  444.         if (lineNode->Fold == NULL) {
  445.  
  446.             // line not yet parsed ?
  447.  
  448.             if (lineNode->Len)
  449.                 if (lineNode->UserData == NULL)
  450.                     lineNode->UserData = DupStack(ParseString(lineNode->Text, lineNode->Len, scanID));
  451.         }
  452.  
  453.         ++lineNode;
  454.     }
  455. }
  456.  
  457. ///
  458. /// "private"
  459.  
  460. /* -------------------------------- PrepareHash --------------------------------
  461.  
  462.  Prepare reserved keyword hashtable (used to find keyword description if ascii
  463.  value of first letter is known).
  464.  
  465. */
  466.  
  467. void
  468. PrepareHash()
  469. {
  470.     struct Keyword *keyword;
  471.  
  472.     memset(Hash, 0, sizeof(Hash));
  473.  
  474.     keyword = Reserved;
  475.  
  476.     while (keyword->Pattern) {
  477.  
  478.         UWORD ascii = *keyword->Pattern;
  479.  
  480.         Hash[ascii] = keyword;
  481.  
  482.         // ignore keywords starting with the same letter
  483.  
  484.         while (keyword->Pattern && (*keyword->Pattern == ascii)) {
  485.  
  486.             keyword->Len = strlen(keyword->Pattern);
  487.  
  488.             ++keyword;
  489.         }
  490.     }
  491. }
  492.  
  493.  
  494. /* -------------------------------- ParseString --------------------------------
  495.  
  496.  Parse a string, build a syntax description. This is a simple example only:
  497.  C++-Comments (// ....) are highlighted. Return EMPTY_STACK in case there is
  498.  nothing to highlight.
  499.  
  500. */
  501.  
  502. struct SyntaxChunk *
  503. ParseString(UBYTE *text, UWORD len, ULONG scanID)
  504. {
  505.     if (len) {
  506.  
  507.         UWORD indent, elements, section;
  508.  
  509.         BOOL readOpcode   = FALSE;
  510.         BOOL readArgs     = FALSE;
  511.         BOOL readComment  = FALSE;
  512.  
  513.         struct SyntaxChunk *syntaxStack = ((struct BufferHandle *)scanID)->bh_SyntaxStack;
  514.  
  515.         // leading spaces have to be ignored
  516.  
  517.         for (indent = 0; len && (*text == 32); ++indent, --len)
  518.             ++text;
  519.  
  520.         // trailing spaces have to be ignored
  521.  
  522.         while (len && (text[len - 1] == 32))
  523.             --len;
  524.  
  525.         if (len) {
  526.  
  527.             if (*text == '*') {
  528.  
  529.                 // comment detected (ignore rest of line)
  530.  
  531.                 syntaxStack[0].sc_Level = SYNTAX_COMMENTLONG;
  532.                 syntaxStack[0].sc_Start = indent;
  533.                 syntaxStack[0].sc_End   = indent + len - 1;
  534.  
  535.                 elements = 1;
  536.             }
  537.             else {
  538.  
  539.                 section = 0;
  540.  
  541.                 for (elements = 0; len; ++text, ++indent, --len) {
  542.  
  543.                     if ((*text == 34) || (*text == 39)) {
  544.  
  545.                         // string (argument) detected
  546.  
  547.                         UWORD stringLen = 1;
  548.  
  549.                         while (stringLen < len)
  550.                             if (text[stringLen++] == *text)
  551.                                 break;
  552.  
  553.                         if (readArgs) {
  554.  
  555.                             syntaxStack[elements].sc_Level = SYNTAX_ARGUMENTS;
  556.                             syntaxStack[elements].sc_Start = indent;
  557.                             syntaxStack[elements].sc_End   = indent + stringLen - 1;
  558.  
  559.                             ++elements;
  560.                         }
  561.  
  562.                         // move to next section (consider end-of-loop action)
  563.  
  564.                         --stringLen;
  565.  
  566.                         text   += stringLen;
  567.                         indent += stringLen;
  568.                         len    -= stringLen;
  569.                     }
  570.                     else if (*text == ';') {
  571.  
  572.                         // comment detected (rest of line)
  573.  
  574.                         syntaxStack[elements].sc_Level = SYNTAX_COMMENTSHORT;
  575.                         syntaxStack[elements].sc_Start = indent;
  576.                         syntaxStack[elements].sc_End   = indent + len - 1;
  577.  
  578.                         ++elements;
  579.  
  580.                         // terminate parsing
  581.  
  582.                         break;
  583.                     }
  584.                     else if (*text != 32) {
  585.  
  586.                         // examine next word
  587.  
  588.                         UWORD wordLen, baseLen = 0;
  589.  
  590.                         for (wordLen = 1; (text[wordLen] != 32) && (wordLen < len); ++wordLen) {
  591.  
  592.                             if (text[wordLen] == '.')
  593.                                 baseLen = wordLen;
  594.                         }
  595.  
  596.                         if ((section == 0) && ((indent == 0) || (text[wordLen - 1] == ':'))) {
  597.  
  598.                             // label detected: local or global label ?
  599.  
  600.                             if ((*text == '.') || (text[wordLen - 1] == '$'))
  601.                                 syntaxStack[elements].sc_Level = SYNTAX_LABELLOCAL;
  602.                             else
  603.                                 syntaxStack[elements].sc_Level = SYNTAX_LABELGLOBAL;
  604.  
  605.                             syntaxStack[elements].sc_Start = indent;
  606.                             syntaxStack[elements].sc_End   = indent + wordLen - 1;
  607.  
  608.                             ++elements;
  609.  
  610.                             readOpcode = TRUE;
  611.                         }
  612.                         else if (readComment) {
  613.  
  614.                             // syntax error: comment expected
  615.                         }
  616.                         else if (readArgs) {
  617.  
  618.                             // found arguments
  619.  
  620.                             syntaxStack[elements].sc_Level = SYNTAX_ARGUMENTS;
  621.                             syntaxStack[elements].sc_Start = indent;
  622.                             syntaxStack[elements].sc_End   = indent + wordLen - 1;
  623.  
  624.                             ++elements;
  625.  
  626.                             readComment = TRUE;
  627.                         }
  628.                         else {
  629.  
  630.                             // found opcode
  631.  
  632.                             syntaxStack[elements].sc_Level = CheckOpcode(text, wordLen, baseLen);
  633.                             syntaxStack[elements].sc_Start = indent;
  634.                             syntaxStack[elements].sc_End   = indent + wordLen - 1;
  635.  
  636.                             ++elements;
  637.  
  638.                             readArgs = TRUE;
  639.                         }
  640.  
  641.                         // move to next section (consider end-of-loop action)
  642.  
  643.                         --wordLen;
  644.                         ++section;
  645.  
  646.                         text   += wordLen;
  647.                         indent += wordLen;
  648.                         len    -= wordLen;
  649.                     }
  650.                 }
  651.             }
  652.  
  653.             if (elements) {
  654.  
  655.                 // terminate syntax stack
  656.  
  657.                 syntaxStack[elements].sc_Start = FALSE;
  658.                 syntaxStack[elements].sc_End   = FALSE;
  659.                 syntaxStack[elements].sc_Level = FALSE;
  660.  
  661.                 return(syntaxStack);
  662.             }
  663.             else
  664.                 return(EMPTY_STACK);
  665.         }
  666.     }
  667.  
  668.     return(EMPTY_STACK);
  669. }
  670.  
  671. /* --------------------------------- DupStack ----------------------------------
  672.  
  673.  Duplicate syntax stack (to be FreeVec'ed). Return NULL in case of failure.
  674.  
  675. */
  676.  
  677. struct SyntaxChunk *
  678. DupStack(syntaxStack)
  679.  
  680. struct SyntaxChunk *syntaxStack;
  681. {
  682.     if (syntaxStack && (syntaxStack != EMPTY_STACK)) {
  683.  
  684.         struct SyntaxChunk *chunk;
  685.         UWORD               elements;
  686.  
  687.         // determine stack size
  688.  
  689.         for (elements = 0, chunk = syntaxStack; chunk->sc_Level; ++chunk)
  690.             ++elements;
  691.  
  692.         // create copy of syntax stack (to be attached to a text line by the caller)
  693.  
  694.         if (elements) {
  695.  
  696.             ULONG size = (++elements) * sizeof(struct SyntaxChunk);
  697.  
  698.             chunk = syntaxStack;
  699.  
  700.             if (syntaxStack = AllocVec(size, MEMF_PUBLIC))
  701.                 movmem(chunk, syntaxStack, size);
  702.         }
  703.         else
  704.             syntaxStack = EMPTY_STACK;
  705.     }
  706.  
  707.     return(syntaxStack);
  708. }
  709.  
  710.  
  711. /* -------------------------------- CheckOpcode --------------------------------
  712.  
  713.  Check opcode, return syntax level.
  714.  
  715. */
  716.  
  717. UWORD
  718. CheckOpcode(text, wordLen, baseLen)
  719.  
  720. UBYTE *text;
  721. UWORD  wordLen, baseLen;
  722. {
  723.     struct Keyword *keyword;
  724.     UWORD           first;
  725.  
  726.     first = UPPER(*text);
  727.  
  728.     // is there a known opcode starting with the same letter ?
  729.  
  730.     if (keyword = Hash[first]) {
  731.  
  732.         UWORD syntaxLevel = SYNTAX_OPCODE;
  733.  
  734.         // no opcode extension (e.g. ".l") ?
  735.  
  736.         if (baseLen == 0)
  737.             baseLen = wordLen;
  738.  
  739.         // search sorted list of known opcodes
  740.  
  741.         while (keyword->Pattern) {
  742.  
  743.             if (*keyword->Pattern > first)
  744.  
  745.                 break;
  746.  
  747.             else if (*keyword->Pattern == first) {
  748.  
  749.                 if (keyword->Len == baseLen)
  750.                     if (memicmp(text, keyword->Pattern, baseLen))
  751.                         return(keyword->Level);
  752.             }
  753.  
  754.             ++keyword;
  755.         }
  756.  
  757.         return(syntaxLevel);
  758.     }
  759.     else
  760.         return(SYNTAX_OPCODE);
  761. }
  762.  
  763.  
  764. /* ---------------------------------- memicmp ----------------------------------
  765.  
  766.  case-insensitive memcmp replacement (<pattern> is supposed to be uppercase).
  767.  Return TRUE if <text> equals <pattern>.
  768.  
  769. */
  770.  
  771. BOOL
  772. memicmp(text, pattern, len)
  773.  
  774. UBYTE *text, *pattern;
  775. UWORD  len;
  776. {
  777.     while (len--)
  778.         if (UPPER(*text++) != *pattern++)
  779.             return(FALSE);
  780.  
  781.     return(TRUE);
  782. }
  783.  
  784. ///
  785.