** Amiga Syntax-Parser for GoldEd
** by Sebatian Rittau in 1996
**
** EMail: srittau@jroger.in-berlin.de
**
**
** THIS SOURCECODE IS FREEWARE
** YOU MUST NOT REDISTRIBUTE CHANGED VERSIONS OF THIS SOURCECODE OR THE
** LIBRARY

  SECTION       lib,CODE

                                 ** Includes **

  INCDIR        INCLUDE:

  IFND EXEC_NODES_I
                INCLUDE     'exec/nodes.i'
  ENDC
  IFND EXEC_LIBRARIES_I
                INCLUDE     'exec/libraries.i'
  ENDC
  IFND EXEC_RESIDENT_I
                INCLUDE     'exec/resident.i'
  ENDC
  IFND EXEC_INITIALIZERS_I
                INCLUDE     'exec/initializers.i'
  ENDC
  IFND LIB_EXEC_I
                INCLUDE     'lib/exec.i'
  ENDC
         INCLUDE   'lib/intuition.i'   ;!!!

                                 ** golded.s **

         STRUCTURE LineNode,0
                   UWORD     Len
                   ULONG     Line
                   LONG      Text
                   LONG      SpecialInfo
                   APTR      UserData
         LABEL     LineNode_SIZE


         STRUCTURE SpecialInfo,0
                   UWORD     ID
         LABEL     SpecialInfo_SIZE


EXTENSION_FOLD     EQU       0
EXTENSION_BREAK    EQU       1

; some useful macros

         MACRO     ISFOLD
                   move.l    a0,-(sp)
                   move.l    SpecialInfo(\1),d0
                   beq       .ISFOLDend
                   cmp.w     #EXTENSION_FOLD,ID(a0)
                   beq       .ISFOLDok
                   moveq.l   #0,d0
                   bra       .ISFOLDend
.ISFOLDok          moveq.l   #1,d0
.ISFOLDend         move.l    (sp)+,a0
         ENDM

                                ** scanlib.s **

PARSER_MAGIC       EQU       "GED4"

; library base

         STRUCTURE ParserBase,LIB_SIZE
                   UWORD     pad
                   ULONG     Magic
         LABEL     ParserBase_SIZE

; description of parser abilities

         STRUCTURE ParserData,0
                   ULONG     pd_Release
                   ULONG     pd_Version
                   ULONG     pd_Serial
                   LONG      pd_Info
                   UWORD     pd_Levels
                   LONG      pd_Names
                   LONG      pd_Colors
                   BOOL      pd_Flags
                   LONG      pd_Example
         LABEL     ParserData_SIZE

SCANLIBVERSION     EQU       4

; syntax chunk created by scanner

         STRUCTURE SyntaxChunk,0
                   UWORD     sc_Start
                   UWORD     sc_End
                   UWORD     sc_Level
         LABEL     SyntaxChunk_SIZE

                                ** Constants **

SYSBASE            EQU       4

;!version!
VERSION            EQU       0
REVISION           EQU       10
PRIORITY           EQU       0

                             ** Security-Blocker **

secblocker         moveq.l   #-1,d0
                   rts


; !release!
;         INCDIR    hd1:programmierung/assembler/projekte/makros
;         INCLUDE   'debug.i'

                               ** Strings **

libname            dc.b      'AmigaE.parser',0
                   even
;!version! !date!
libversion         dc.b      'AmigaE.parser 0.10 [beta] (21.8.96)',$0D,$0A,0
                   even

                                ** ROMTag **

romtag             dc.w      RTC_MATCHWORD
                   dc.l      romtag
                   dc.l      libend
                   dc.b      0
                   dc.b      VERSION
                   dc.b      NT_LIBRARY
                   dc.b      PRIORITY
                   dc.l      libname
                   dc.l      libversion
                   dc.l      func_init

                         ** Function-Declaration **

functionlist       dc.l      func_Open
                   dc.l      func_Close
                   dc.l      func_Expunge
                   dc.l      func_ExtFunc

                   dc.l      func_MountScanner
                   dc.l      func_StartScanner
                   dc.l      func_CloseScanner
                   dc.l      func_FlushScanner
                   dc.l      func_SetupScanner
                   dc.l      func_BriefScanner
                   dc.l      func_ParseLine
                   dc.l      func_UnparseLines
                   dc.l      func_ParseSection

                   dc.l      -1

***************************************************************************
**                             Initialization                            **
***************************************************************************

func_init          movem.l   a1-a2/a6/d1-d2,-(sp)
                   move.l    a0,seglist

                   lea.l     functionlist,a0
                   suba.l    a1,a1
                   movea.l   a1,a2
                   move.l    #ParserBase_SIZE,d0
                   moveq.l   #0,d1
                   jsr       _LVOMakeLibrary(a6)
                   tst.l     d0
                   beq       .end

                   movea.l   d0,a6
                   move.b    #NT_LIBRARY,LN_TYPE(a6)
                   move.l    #libname,LN_NAME(a6)
                   move.b    #LIBF_CHANGED|LIBF_SUMUSED,LIB_FLAGS(a6)
                   move.w    #VERSION,LIB_VERSION(a6)
                   move.w    #REVISION,LIB_REVISION(a6)
                   move.l    #libversion,LIB_IDSTRING(a6)
                   move.l    #PARSER_MAGIC,Magic(a6)

                   move.l    a6,d2
                   movea.l   d2,a1
                   movea.l   4.w,a6
                   jsr       _LVOAddLibrary(a6)

                   move.l    d2,d0
.end               move.l    seglist,a0
                   movem.l   (sp)+,a1-a2/a6/d1-d2
                   rts

seglist            dc.l      0

***************************************************************************
**                           General Functions                           **
***************************************************************************

                     ** Open(a6=ownbase,d0=version) **

func_Open       movem.l     d1/a6,-(sp)
                addq.w      #1,LIB_OPENCNT(a6)
                bclr        #LIBB_DELEXP,LIB_FLAGS(a6)
                movem.l     (sp)+,d1/a6
                move.l      a6,d0
                rts

                          ** Close(a6=ownbase) **

func_Close      clr.l       d0
                subq.w      #1,LIB_OPENCNT(a6)  ; library open?
                bne.s       .end
                btst        #LIBB_DELEXP,LIB_FLAGS(a6)  ; is there a delayed expunge?
                beq.s       .end
                bsr.s       func_Expunge
.end            rts

                         ** Expunge(a6=ownbase) **

func_Expunge    movem.l     d2/a5-a6,-(sp)      ; save registers
                tst.w       LIB_OPENCNT(a6)     ; library open?
                beq.s       .doit
                bset        #LIBB_DELEXP,LIB_FLAGS(a6) ; set delayed expunge flag
                clr.l       d0                  ; return error
                bra.s       .end
.doit           movea.l     a6,a5               ; ownbase to a5
                movea.l     SYSBASE,a6          ; execbase to a6
                movea.l     a5,a1               ; ownbase to a1
                jsr         _LVORemove(a6)      ; Remove(a1=ownbase)
                move.l      seglist,d2          ; seglist-contents to d2
                movea.l     a5,a1               ; ownbase to a1
                clr.l       d0                  ; clear d0
                move.w      LIB_NEGSIZE(a5),d0  ; # bytes before ownbase to d0
                suba.l      d0,a1               ; beginning of library in a1
                add.w       LIB_POSSIZE(a5),d0  ; # bytes after ownbase to d0
                jsr         _LVOFreeMem(a6)     ; FreeMem(a1=beginning of lib,d0=# bytes after ownbase)
                move.l      d2,d0               ; return seglist
.end            movem.l     (sp)+,d2/a5-a6      ; get back registers
                rts

                              ** ExtFunc() **

func_ExtFunc    moveq.l     #0,d0
                rts

***************************************************************************
**                             End of Library                            **
***************************************************************************

libend

***************************************************************************
*                               Custom Functions                          *
***************************************************************************

                              ** MountScanner() **

; !version!
libinfo            dc.b      'AmigaE.parser 0.10 [beta]'
                   even

levelnames         dc.l      .standardtext,.shortcomment,.longcomment,.vars,.keywords,.functions,.numconstants,.strings,.characters,.preprocessor,0
.standardtext      dc.b      'Standard text',0
.shortcomment      dc.b      'Short Comments (->)',0
.longcomment       dc.b      'Long Comments (/*...*/)',0
.vars              dc.b      'Variables (xyz)',0
.keywords          dc.b      'Keywords/Constants (XYZ)',0
.functions         dc.b      'Functions (Xyz)',0
.numconstants      dc.b      'Numeric constants',0
.strings           dc.b      'Strings (',39,'...',39,')',0
.characters        dc.b      'Characters ("ABCD")',0
.preprocessor      dc.b      'Preprocessor (#xyz)',0
                   even
levelcolors        dc.l      $000,$fff,$aaa,$00f,$0f0,$0f0,$000,$ff0,$000,$000

exampletext        dc.l      .ex1,.ex2,.ex3,.ex4,.ex5,.ex6,.ex7,.ex8,.ex9,.ex10,0
.ex1               dc.b      '/* AmigaE Program */',0
.ex2               dc.b      0
.ex3               dc.b      '#define MYSTRING ',39,'Hello world!\\n',39,0
.ex4               dc.b      'CONST MYCONST=5',0
.ex5               dc.b      0
.ex6               dc.b      '-> main-procedure',0
.ex7               dc.b      'PROC main()',0
.ex8               dc.b      '  DEF x',0
.ex9               dc.b      '  IF x="MAIN" THEN WriteF(MYSTRING)',0
.ex10              dc.b      'ENDPROC',0
                   even

parserdata
                   dc.l      SCANLIBVERSION
                   dc.l      VERSION
                   dc.l      0
                   dc.l      libinfo
                   dc.w      10
                   dc.l      levelnames
                   dc.l      levelcolors
                   dc.w      0
                   dc.l      exampletext

func_MountScanner
                   move.l    #parserdata,d0
                   rts

                       ** StartScanner(D0:SyntaxStack) **

func_StartScanner
                   ; moveq.l   d0,d0
                   rts

                       ** CloseScanner(D0:SyntaxStack) **

func_CloseScanner
                   moveq.l   #0,d0
                   rts

                              ** FlushScanner() **

func_FlushScanner
                   rts

                              ** SetupScanner() **

func_SetupScanner
                   rts

                              ** BriefScanner() **

func_BriefScanner
                   moveq.l   #0,d0
                   rts

                  ** ParseLine(D0:SyntaxChunk,A0:LineNode) **

func_ParseLine     movem.l   d1/a0-a1,-(sp)
                   move.l    d0,a1
                   ISFOLD    a0
                   tst.l     d0
                   bne       .end
                   moveq.l   #0,d0
                   move.w    Len(a0),d0
                   beq       .error
                   movea.l   Text(a0),a0
                   bsr       parseline
                   bra       .end
.error             moveq.l   #0,d0
.end               movem.l   (sp)+,d1/a0-a1
                   rts

                              ** UnparseLines() **

func_UnparseLines  rts

                              ** ParseSection() **

func_ParseSection  rts

***************************************************************************
**                                  Parsing                              **
***************************************************************************

                     ** d0: len, a0: string, a1: syntax **

** d0: len, d1: offset
parseline
                   movem.l   d1-d2/a0-a1,-(sp)
                   moveq.w   #0,d1
                   bsr       cutwhites

                   cmp.w     #0,d0
                   beq       .end
                   cmp.b     #"#",(a0)
                   bne       .skipwhites
                   bsr       .preprocessor
                   bra       .loop

.skipwhites        bsr       skipwhites

.loop
                   cmp.w     #0,d0
                   beq       .end
                   ; String?
                   cmp.b     #"'",(a0)
                   bne       .nostring
                   bsr       .string
                   bra       .loop
.nostring
                   ; Characters?
                   cmp.b     #34,(a0)
                   bne       .checklt2
                   bsr       .characters
                   bra       .loop
.checklt2          cmp.w     #2,d0
                   blt       .lt2
                   ; -> Comment?
                   cmp.w     #"->",(a0)
                   beq       .shortcomment
                   ; /* Comment?
                   cmp.w     #"/*",(a0)
                   beq       .longcomment
                   ; Keywords & Constants
                   cmp.b     #"A",(a0)
                   blt       .lt2
                   cmp.b     #"Z",(a0)
                   bgt       .lt2
                   cmp.b     #"0",1(a0)
                   blt       .tstfunc
                   cmp.b     #"Z",1(a0)
                   bgt       .tstfunc
                   cmp.b     #"A",1(a0)
                   bge       .dokeyword
                   cmp.b     #"9",1(a0)
                   bgt       .tstfunc
.dokeyword         bsr       .keyword
                   bra       .loop
.tstfunc           ; Functions
                   cmp.b     #"a",1(a0)
                   blt       .lt2
                   cmp.b     #"z",1(a0)
                   bgt       .lt2
                   bsr       .function
                   bra       .loop
                   ; Variable?
.lt2               cmp.b     #"a",(a0)
                   blt       .novar
                   cmp.b     #"z",(a0)
                   bgt       .novar
                   bsr       .variable
                   bra       .loop
.novar
                   ; numeric constant?
                   cmp.b     #"0",(a0)
                   blt       .nonumconst
                   cmp.b     #"9",(a0)
                   bgt       .nonumconst
                   bsr       .numconstant
                   bra       .loop
.nonumconst

                   ; go on in loop
                   subq.w    #1,d0
                   add.l     #1,a0
                   add.w     #1,d1
                   bra       .loop

.end               move.l    #0,sc_Level(a1)
                   move.l    #0,sc_Start(a1)
                   move.l    #0,sc_End(a1)
                   movem.l   (sp)+,d1-d2/a0-a1
                   move.l    a1,d0
                   rts

** short comment

.shortcomment
                   move.w    #1,sc_Level(a1)
                   move.w    d1,sc_Start(a1)
                   move.w    d1,sc_End(a1)
                   add.w     d0,sc_End(a1)
                   sub.w     #1,sc_End(a1)
                   adda.l    #SyntaxChunk_SIZE,a1
                   bra       .end

** long comment

.longcomment       moveq.l   #0,d0
                   bra       .end

** variables

.variable          move.w    #3,sc_Level(a1)
                   move.w    d1,sc_Start(a1)
                   bsr       wordlen
                   move.w    d1,sc_End(a1)
                   sub.w     #1,sc_End(a1)
                   adda.l    #SyntaxChunk_SIZE,a1
                   rts

** keywords & constants

.keyword           move.w    #4,sc_Level(a1)
                   move.w    d1,sc_Start(a1)
                   bsr       wordlenkey
                   move.w    d1,sc_End(a1)
                   sub.w     #1,sc_End(a1)
                   adda.l    #SyntaxChunk_SIZE,a1
                   rts

** functions

.function          move.w    #5,sc_Level(a1)
                   move.w    d1,sc_Start(a1)
                   bsr       wordlen
                   move.w    d1,sc_End(a1)
                   sub.w     #1,sc_End(a1)
                   adda.l    #SyntaxChunk_SIZE,a1
                   rts

** numeric constants

.numconstant       move.w    #6,sc_Level(a1)
                   move.w    d1,sc_Start(a1)
.numconstloop      adda.l    #1,a0
                   addq.w    #1,d1
                   subq.w    #1,d0
                   tst.w     d0
                   beq       .numconstend
                   cmp.b     #".",(a0)
                   beq       .numconstloop
                   cmp.b     #"0",(a0)
                   blt       .numconstend
                   cmp.b     #"9",(a0)
                   bgt       .numconstend
                   bra       .numconstloop
.numconstend       move.w    d1,sc_End(a1)
                   sub.w     #1,sc_End(a1)
                   adda.l    #SyntaxChunk_SIZE,a1
                   rts

** strings

.string            move.w    #7,sc_Level(a1)
                   move.w    d1,sc_Start(a1)
.stringloop        adda.l    #1,a0
                   addq.w    #1,d1
                   subq.w    #1,d0
                   tst.w     d0
                   beq       .stringend
                   cmp.b     #"'",(a0)
                   bne       .stringloop
                   adda.l    #1,a0
                   addq.w    #1,d1
                   subq.w    #1,d0
.stringend         move.w    d1,sc_End(a1)
                   sub.w     #1,sc_End(a1)
                   adda.l    #SyntaxChunk_SIZE,a1
                   rts

** characters

.characters        move.w    #8,sc_Level(a1)
                   move.w    d1,sc_Start(a1)
.charloop          adda.l    #1,a0
                   addq.w    #1,d1
                   subq.w    #1,d0
                   tst.w     d0
                   beq       .charend
                   cmp.b     #34,(a0)
                   bne       .charloop
                   adda.l    #1,a0
                   addq.w    #1,d1
                   subq.w    #1,d0
.charend           move.w    d1,sc_End(a1)
                   sub.w     #1,sc_End(a1)
                   adda.l    #SyntaxChunk_SIZE,a1
                   rts

** preprocessor

.preprocessor      move.w    #9,sc_Level(a1)
                   move.w    d1,sc_Start(a1)
                   adda.l    #1,a0
                   subq.l    #1,d0
                   addq.l    #1,d1
                   bsr       wordlen
                   move.w    d1,sc_End(a1)
                   sub.w     #1,sc_End(a1)
                   adda.l    #SyntaxChunk_SIZE,a1
                   rts

***************************************************************************
**                                  Support                              **
***************************************************************************

                   ** D0:len,A0:string=(D0:len,A0:string) **

skipwhites         tst.w     d0
                   beq       .end
                   cmp.b     #$20,(a0)
                   bne       .end
                   subq.w    #1,d0
                   add.l     #1,a0
                   addq.w    #1,d1
                   bra       skipwhites
.end               rts


cutwhites          tst.w     d0
                   beq       .end
                   cmp.b     #$20,-1(a0,d0)
                   bne       .end
                   subq.w    #1,d0
                   add.l     #1,a0
                   bra       cutwhites
.end               rts


wordlen            tst.w     d0
                   beq       .end
                   ; check 0-z
                   cmp.b     #"0",(a0)
                   blt       .end
                   cmp.b     #"z",(a0)
                   bgt       .end
                   ; check Z-a
                   cmp.b     #"Z",(a0)
                   ble       .check2
                   cmp.b     #"a",(a0)
                   blt       .checkunder
.check2            ; check 9-A
                   cmp.b     #"9",(a0)
                   ble       .next
                   cmp.b     #"A",(a0)
                   blt       .end
.next              addq.w    #1,d1
                   adda.l    #1,a0
                   subq.w    #1,d0
                   bra       wordlen
.end               rts

.checkunder        cmp.b     #"_",(a0)
                   bne       .end
                   bra       .next

wordlenkey         tst.w     d0
                   beq       .end
                   ; check 0-z
                   cmp.b     #"0",(a0)
                   blt       .checkpoint
                   cmp.b     #"z",(a0)
                   bgt       .end
                   ; check Z-a
                   cmp.b     #"Z",(a0)
                   ble       .check2
                   cmp.b     #"a",(a0)
                   blt       .checkunder
.check2            ; check 9-A
                   cmp.b     #"9",(a0)
                   ble       .next
                   cmp.b     #"A",(a0)
                   blt       .end
.next              addq.w    #1,d1
                   adda.l    #1,a0
                   subq.w    #1,d0
                   bra       wordlenkey
.end               rts

.checkpoint        cmp.b     #".",(a0)
                   bne       .end
                   bra       .next

.checkunder        cmp.b     #"_",(a0)
                   bne       .end
                   bra       .next

