Beginning ANTLR4 definition for the Clarion language

Greetings - Here is the latest grammar from last night passed through http://lab.antlr.org/ with no errors. The grammar is not complete, but it will parse the clarion minimal program.
Regards,
Roberto Artigas

grammar ClarionGrammar;

options { caseInsensitive = true; }

// Parser rules

program
    : programHeader
      lineEnd*               // allow blank lines after PROGRAM
      mapSection?
      (lineEnd | declarationSection)*  // allow interleaved blank lines and declarations
      codeSection
      lineEnd*               // allow trailing blank lines
      EOF
    ;

programHeader
    : PROGRAM
    ;

lineEnd
    : EOL
    | NEWLINE
    ;

// MAP section

mapSection
    : MAP mapEntry* (END | DOT)
    ;

mapEntry
    : moduleDecl
    | prototypeDecl
    ;

moduleDecl
    : MODULE LPAREN expr? RPAREN lineEnd?
      prototypeDecl*
      (END | DOT)
    ;

// MAP prototypes

prototypeDecl
    : ID LPAREN prototypeParamList? RPAREN (COMMA returnType)? (COMMA PROC)? lineEnd?
    ;

prototypeParamList
    : prototypeParam (COMMA prototypeParam)*
    ;

prototypeParam
    : ( STAR typeSpec
      | typeSpec
      | LT STAR typeSpec GT
      | LT typeSpec GT
      )
      (EQUAL expr)?
    ;

// Types

typeSpec
    : BYTE
    | SHORT
    | USHORT
    | LONG
    | ULONG
    | DECIMAL
    | PDECIMAL
    | REAL
    | SREAL
    | BFLOAT8
    | BFLOAT4
    | STRINGKW
    | CSTRING
    | BSTRING
    | PSTRING
    | USTRING
    | BLOB
    | MEMO
    | DATE
    | TIME
    | BOOL
    | GROUP
    | QUEUE
    | FILE
    | VIEW
    | WINDOW
    | VARIANT
    | ANY
    | refType
    | ID
    | QUESTION   // allow ? as a parameter type
    ;

// Reference types: &BYTE, &STRING, &QUEUE, &FILE, &VIEW, &WINDOW, etc.
refType
    : AMP (
          BYTE
        | SHORT
        | USHORT
        | LONG
        | ULONG
        | DATE
        | TIME
        | REAL
        | SREAL
        | BFLOAT8
        | BFLOAT4
        | DECIMAL
        | PDECIMAL
        | STRINGKW
        | CSTRING
        | PSTRING
        | GROUP
        | QUEUE
        | FILE
        | KEYKW
        | BLOB
        | VIEW
        | WINDOW
        | USTRING
        | BSTRING
        | VARIANT
      )
    ;

builtinType
    : BYTE
    | SHORT
    | USHORT
    | LONG
    | ULONG
    | DECIMAL
    | PDECIMAL
    | REAL
    | SREAL
    | BFLOAT8
    | BFLOAT4
    | STRINGKW
    | CSTRING
    | BSTRING
    | PSTRING
    | USTRING
    | BLOB
    | MEMO
    | DATE
    | TIME
    | BOOL
    | GROUP
    | QUEUE
    | FILE
    | VIEW
    | WINDOW
    | VARIANT
    | ANY
    ;

// Data type arguments and STRING/DECIMAL/PDECIMAL syntax

dataLikeOrType
    : LIKE LPAREN fieldRef RPAREN
    | STRINGKW stringTypeArgs?
    | typeSpec typeArgs?
    ;

// DECIMAL/PDECIMAL and generic arg lists (trimmed ambiguity)
typeArgs
    : LPAREN argList? RPAREN
    ;

// STRING( string-constant | length-expr | picture )
stringTypeArgs
    : LPAREN stringArg RPAREN
    ;

stringArg
    : STRING        // string constant
    | PICTURE       // picture like @s10, @n3
    | expr          // length expression
    ;

// Procedure parameter lists for PROCEDURE / methods

procedureProtoParamList
    : procedureProtoParam (COMMA procedureProtoParam)*
    ;

procedureProtoParam
    : typeSpec (ID)? (EQUAL expr)?
    ;

// Declarations

declarationSection
    : dataDecl
    | likeNewDecl
    | queueDecl
    | windowDecl
    | reportDecl
    | procedureDecl
    | labelDecl
    | itemizeDecl
    | recordDecl
    | groupDecl
    | fileDecl
    | viewDecl
    | interfaceDecl
    | classDecl
    | keywordDecl
    ;

// DATA

dataDecl
    : ID dataLikeOrType? (COMMA dataAttr)* lineEnd
    ;

// LIKE-only declaration
likeNewDecl
    : LIKE LPAREN fieldRef RPAREN (COMMA dataAttr)* lineEnd
    ;

argList
    : expr (COMMA expr)*
    ;

dataAttr
    : PRE LPAREN ID RPAREN
    | USE LPAREN fieldRef RPAREN
    | DIM LPAREN expr (COMMA expr)* RPAREN
    | OVER LPAREN fieldRef RPAREN
    | STATIC
    | PRIVATE
    | THREAD
    | AUTO
    | BINARYKW
    | EXTERNAL
    | DLL LPAREN argList? RPAREN
    | PROTECTED
    | ID (LPAREN argList? RPAREN)?
    ;

// QUEUE

queueDecl
    : ID QUEUE queueTypeArgs? (COMMA queueAttr)* lineEnd
      queueFieldDecl+
      (END | DOT)
    ;

queueTypeArgs
    : LPAREN fieldRef? RPAREN
    ;

queueAttr
    : PRE (LPAREN ID RPAREN)?
    | STATIC
    | THREAD
    | TYPEKW
    | BINDABLE
    | EXTERNAL
    | DLL (LPAREN argList? RPAREN)?
    | ID (LPAREN argList? RPAREN)?
    ;

queueFieldDecl
    : ID dataLikeOrType? (COMMA dataAttr)* lineEnd
    ;

// WINDOW

windowDecl
    : ID WINDOW windowArgs? lineEnd
      windowMenuBarSection?
      windowToolBarSection?
      windowControlDecl*
      (END | DOT)
    ;

windowArgs
    : LPAREN argList? RPAREN (COMMA windowAttr)*
    ;

windowAttr
    : ATKW      LPAREN argList? RPAREN
    | FONTKW    LPAREN argList? RPAREN
    | ICONKW    LPAREN argList? RPAREN
    | STATUSKW  LPAREN argList? RPAREN
    | HLPKW     LPAREN argList? RPAREN
    | CURSORKW  LPAREN argList? RPAREN
    | TIMERKW   LPAREN argList? RPAREN
    | ALRTKW    LPAREN argList? RPAREN
    | MSGKW     LPAREN argList? RPAREN
    | PALETTEKW LPAREN argList? RPAREN
    | DROPIDKW  LPAREN argList? RPAREN
    | DOCKKW    LPAREN argList? RPAREN
    | DOCKEDKW  LPAREN argList? RPAREN
    | LAYOUTKW  LPAREN argList? RPAREN
    | COLORKW   LPAREN argList? RPAREN
    | CENTER
    | CENTERED
    | SYSTEMKW
    | MAXKW
    | MDI
    | MODAL
    | MASK
    | GRAY
    | ICONIZE
    | MAXIMIZE
    | IMMKW
    | AUTO
    | TOOLBOX
    | TILED
    | HSCROLL
    | VSCROLL
    | NOFRAME
    | HVSCROLL
    | RESIZEKW
    | DOUBLE
    | ID (LPAREN argList? RPAREN)?
    ;

// MENUBAR / MENU / ITEM

windowMenuBarSection
    : MENUBAR menubarArgs? lineEnd
      menuBarEntry*
      (END | DOT)
    ;

menubarArgs
    : (COMMA menubarAttr)+
    ;

menubarAttr
    : USE LPAREN argList? RPAREN
    | NOMERGEKW
    ;

menuBarEntry
    : menuDecl
    | menuItemDecl
    | windowMenuDecl
    ;

menuDecl
    : MENU LPAREN argList? RPAREN menuArgs? lineEnd
      menuEntry*
      (END | DOT)
    ;

menuArgs
    : (COMMA menuAttr)+
    ;

menuAttr
    : ATKW      LPAREN argList? RPAREN
    | USE       LPAREN argList? RPAREN
    | KEYKW     LPAREN argList? RPAREN
    | MSGKW     LPAREN argList? RPAREN
    | HLPKW     LPAREN argList? RPAREN
    | STDKW     (LPAREN argList? RPAREN)?
    | RIGHTKW
    | DISABLEKW
    | COLORKW   (LPAREN argList? RPAREN)?
    | LEFTKW    LPAREN argList? RPAREN
    | HIDEKW
    | ICONKW    LPAREN argList? RPAREN
    | FONTKW    LPAREN argList? RPAREN
    | FIRSTKW
    | LASTKW
    ;

menuEntry
    : menuItemDecl
    | menuDecl
    ;

menuItemDecl
    : ITEMKW LPAREN argList? RPAREN itemArgs? lineEnd
    ;

itemArgs
    : (COMMA itemAttr)+
    ;

itemAttr
    : ATKW      LPAREN argList? RPAREN
    | USE       LPAREN argList? RPAREN
    | KEYKW     LPAREN argList? RPAREN
    | MSGKW     LPAREN argList? RPAREN
    | HLPKW     LPAREN argList? RPAREN
    | STDKW
    | CHECKKW
    | DISABLEKW
    | COLORKW
    | LEFTKW    LPAREN argList? RPAREN
    | HIDEKW
    | SEPARATORKW
    | ICONKW    LPAREN argList? RPAREN
    | FONTKW    LPAREN argList? RPAREN
    | FIRSTKW
    | LASTKW
    ;

windowMenuDecl
    : ID (LPAREN argList? RPAREN)?
      (COMMA ID (LPAREN argList? RPAREN)?)* lineEnd
    ;

// TOOLBAR

windowToolBarSection
    : TOOLBAR toolbarArgs? lineEnd
      windowControlDecl*
      (END | DOT)
    ;

toolbarArgs
    : (COMMA toolbarAttr)+
    ;

toolbarAttr
    : ATKW      LPAREN argList? RPAREN
    | USE       LPAREN argList? RPAREN
    | CURSORKW  LPAREN argList? RPAREN
    | FONTKW    LPAREN argList? RPAREN
    | NOMERGEKW
    | COLORKW
    | LAYOUTKW (LPAREN argList? RPAREN)?
    | WALLPAPERKW LPAREN argList? RPAREN
    | TILED
    | CENTERED
    ;

// Controls (WINDOW)

windowControlDecl
    : oleControlDecl
    | listControlDecl
    | lineControlDecl
    | sheetControlDecl
    | optionControlDecl
    | ID? PROMPTKW LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? BUTTON  LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? STRINGKW LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? CHECKKW LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? IMAGE LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? PANEL LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? PROGRESS LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? REGION LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? SLIDER LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? SPIN LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? controlType controlAttrs lineEnd
    ;

// OPTION control with nested controls
optionControlDecl
    : ID? OPTIONKW optionAttrs? lineEnd
      windowControlDecl*
      (END | DOT)
    ;

optionAttrs
    : COMMA optionAttr (COMMA optionAttr)*
    ;

optionAttr
    : ATKW      LPAREN argList? RPAREN
    | USE       LPAREN argList? RPAREN
    | FONTKW    LPAREN argList? RPAREN
    | COLORKW   LPAREN argList? RPAREN
    | BOXEDKW
    | BEVELKW
    | HIDEKW
    | DISABLEKW
    | ID (LPAREN argList? RPAREN)?
    ;

// Special OLE control with optional nested MENUBAR and END
oleControlDecl
    : ID? OLE oleControlAttrs lineEnd
      oleMenuBarSection?
      (END | DOT)
    ;

oleControlAttrs
    : COMMA ATKW LPAREN argList? RPAREN (COMMA controlAttr)*
    ;

oleMenuBarSection
    : MENUBAR menubarArgs? lineEnd
      menuBarEntry*
      (END | DOT)
    ;

listControlDecl
    : ID? LIST listControlAttrs lineEnd
    ;

listControlAttrs
    : COMMA ATKW LPAREN argList? RPAREN (COMMA controlAttr)*
    ;

lineControlDecl
    : ID? LINE lineControlAttrs lineEnd
    ;

lineControlAttrs
    : COMMA ATKW LPAREN argList? RPAREN (COMMA controlAttr)*
    ;

// SHEET control with nested TABs
sheetControlDecl
    : ID? SHEETKW sheetControlAttrs lineEnd
      sheetTabDecl+
      (END | DOT)
    ;

sheetControlAttrs
    : COMMA sheetControlAttr (COMMA sheetControlAttr)*
    ;

sheetControlAttr
    : ATKW      LPAREN argList? RPAREN
    | CURSORKW  LPAREN argList? RPAREN
    | USE       LPAREN argList? RPAREN
    | LAYOUTKW  LPAREN argList? RPAREN
    | DISABLEKW
    | KEYKW     LPAREN argList? RPAREN
    | FULLKW
    | SCROLLKW
    | HIDEKW
    | FONTKW    LPAREN argList? RPAREN
    | DROPIDKW  LPAREN argList? RPAREN
    | WIZARDKW
    | SPREADKW
    | HSCROLL
    | JOINKW
    | NOSHEETKW
    | COLORKW   LPAREN argList? RPAREN
    | UPKW
    | DOWNKW
    | LEFTKW (LPAREN argList? RPAREN)?
    | RIGHTKW (LPAREN argList? RPAREN)?
    | ABOVEKW LPAREN argList? RPAREN
    | BELOWKW LPAREN argList? RPAREN
    | IMMKW
    ;

sheetTabDecl
    : ID? TABKW LPAREN argList? RPAREN controlAttrs lineEnd
    ;

controlType
    : BUTTON
    | LIST
    | ENTRY
    | STRINGKW
    | GROUP
    | BOX
    | LINE
    | ELLIPSE
    | OLE
    | PROMPTKW
    | RADIOKW
    | SHEETKW
    | TABKW
    | CHECKKW
    | PROGRESS
    | REGION
    | SLIDER
    | SPIN
    ;

controlAttrs
    : (COMMA controlAttr)+
    ;

// Attributes valid on controls
controlAttr
    // positional / layout / binding / data source
    : ATKW      LPAREN argList? RPAREN
    | CURSORKW  LPAREN argList? RPAREN
    | USE       LPAREN argList? RPAREN
    | LAYOUTKW  LPAREN argList? RPAREN
    | LAYOUTKW
    | FONTKW    LPAREN argList? RPAREN
    | COLORKW   LPAREN argList? RPAREN
    | DROPIDKW  LPAREN argList? RPAREN
    | ANGLEKW   LPAREN argList? RPAREN
    | COMPATIBILITYKW LPAREN argList? RPAREN
    | FROMKW    LPAREN argList? RPAREN
    | FORMATKW  LPAREN argList? RPAREN
    | DRAGIDKW  LPAREN argList? RPAREN
    | PENKW     LPAREN argList? RPAREN
    | STYLEKW   LPAREN argList? RPAREN
    | LINEWIDTHKW LPAREN argList? RPAREN
    | LINEWIDTHKW

    // basic behavioral flags
    | DISABLEKW
    | HIDEKW
    | FULLKW
    | SCROLLKW
    | TRNKW
    | SKIPKW
    | DEFAULTKW
    | IMMKW
    | REQKW
    | FLATKW
    | LEFTKW
    | RIGHTKW
    | CENTER
    | READONLYKW
    | MASK
    | INSKW
    | UPRKW
    | OVRKW
    | CAPKW

    // LIST/COMBO-specific simple flags
    | DROPKW
    | COLUMNKW
    | VCRKW
    | NOBARKW
    | GRIDKW (LPAREN argList? RPAREN)?

    // scroll flags usable on controls
    | HSCROLL
    | VSCROLL
    | HVSCROLL

    // BUTTON/menu-style attributes with params
    | KEYKW     LPAREN argList? RPAREN
    | MSGKW     LPAREN argList? RPAREN
    | HLPKW     LPAREN argList? RPAREN
    | STDKW     LPAREN argList? RPAREN
    | ICONKW    LPAREN argList? RPAREN
    | TIPKW     LPAREN argList? RPAREN
    | ALRTKW    LPAREN argList? RPAREN
    | REPEATKW  LPAREN argList? RPAREN
    | DELAYKW   LPAREN argList? RPAREN

    // STRING/report-style aggregation / page counters (using MAXKW)
    | PAGENOKW                          // PAGENO
    | EXTENDKW LPAREN argList? RPAREN   // EXTEND(...)
    | CNTKW    LPAREN argList? RPAREN   // CNT(...)
    | SUMKW    LPAREN argList? RPAREN   // SUM(...)
    | AVEKW    LPAREN argList? RPAREN   // AVE(...)
    | MINKW    LPAREN argList? RPAREN   // MIN(...)
    | MAXKW    LPAREN argList? RPAREN   // MAX(...)
    | RESETKW  LPAREN argList? RPAREN   // RESET(...)
    | TALLYKW  LPAREN argList? RPAREN   // TALLY(...)
    | PAGEKW                            // PAGE
    | DECIMAL                           // DECIMAL flag

    // LIST MARK attribute
    | MARKKW   LPAREN argList? RPAREN

    // ellipse / box / line fill
    | FILLKW   LPAREN argList? RPAREN

    // fallback custom attributes
    | ID (LPAREN argList? RPAREN)?
    ;

// REPORT

reportDecl
    : ID REPORTKW LPAREN argList? RPAREN
      COMMA ATKW LPAREN argList? RPAREN
      (COMMA reportAttr)* lineEnd
      reportSection*
      (END | DOT)
    ;

reportAttr
    : FONTKW   LPAREN argList? RPAREN
    | PRE      LPAREN ID RPAREN
    | LANDSCAPEKW
    | PREVIEWKW
    | PAPERKW
    | COLORKW  LPAREN argList? RPAREN
    | THOUS
    | MMKW
    | POINTSKW
    | ID (LPAREN argList? RPAREN)?
    ;

reportSection
    : reportFormSection
    | reportHeaderSection
    | reportDetailSection
    | reportBreakSection
    | reportFooterSection
    ;

reportFormSection
    : FORMKW lineEnd
      reportControlDecl*
      (END | DOT)
    ;

reportHeaderSection
    : HEADERKW lineEnd
      reportControlDecl*
      (END | DOT)
    ;

reportDetailSection
    : ID DETAILKW lineEnd
      reportControlDecl*
      (END | DOT)
    ;

reportBreakSection
    : ID BREAK LPAREN argList? RPAREN lineEnd
      reportControlDecl*
      (END | DOT)
    ;

reportFooterSection
    : FOOTERKW lineEnd
      reportControlDecl*
      (END | DOT)
    ;

reportControlDecl
    : ID? PROMPTKW LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? BUTTON   LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? STRINGKW LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? CHECKKW  LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? IMAGE    LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? OLE oleControlAttrs lineEnd oleMenuBarSection? (END | DOT)
    | ID? LINE lineControlAttrs lineEnd
    | ID? controlType controlAttrs lineEnd
    ;

// Procedure prototypes and impls

procedureProtoDecl
    : ID PROCEDUREKW (LPAREN procedureProtoParamList? RPAREN)?
      (COMMA returnType)?
      lineEnd
    ;

procedureDecl
    : ID PROCEDUREKW (LPAREN procedureProtoParamList? RPAREN)?
      (COMMA returnType)? lineEnd
      declarationSection*
      codeSection
    ;

returnType
    : STAR? typeSpec
    ;

moduleDecl2
    : MODULE LPAREN expr RPAREN lineEnd
      prototypeDecl*
      (END | DOT)
    ;

// Label / picture / type

labelDecl
    : ID EQUATE LPAREN expr? RPAREN lineEnd
    | PICTURE (COMMA labelAttr)* lineEnd
    | builtinType lineEnd
    ;

labelAttr
    : STATIC
    | THREAD
    | AUTO
    | PRIVATE
    | PROTECTED
    ;

// ITEMIZE

itemizeDecl
    : ID? ITEMIZEKW LPAREN expr? RPAREN
      (COMMA PRE LPAREN expr? RPAREN)?
      lineEnd
      itemizeEquate+
      (END | DOT)
    ;

itemizeEquate
    : ID EQUATE LPAREN expr? RPAREN lineEnd
    ;

// RECORD

recordDecl
    : ID RECORD (COMMA recordAttr)* lineEnd
      recordFieldDecl+
      (END | DOT)
    ;

recordAttr
    : PRE LPAREN ID RPAREN
    | ID (LPAREN argList? RPAREN)?
    ;

recordFieldDecl
    : ID dataLikeOrType? (COMMA dataAttr)* lineEnd
    ;

// GROUP

groupDecl
    : ID? GROUP LPAREN fieldRef? RPAREN (COMMA groupAttr)* lineEnd
      declarationSection*
      (END | DOT)
    ;

groupAttr
    : PRE LPAREN ID RPAREN
    | DIM LPAREN expr (COMMA expr)* RPAREN
    | OVER LPAREN fieldRef RPAREN
    | ID (LPAREN argList? RPAREN)?
    ;

// FILE

fileDecl
    : ID FILE (COMMA fileAttr)* lineEnd
      fileEntry*
      (END | DOT)
    ;

fileAttr
    : PRE LPAREN ID RPAREN
    | ID (LPAREN argList? RPAREN)?
    ;

fileEntry
    : recordDecl
    | fileKeyDecl
    | fileIndexDecl
    | fileMemoDecl
    | fileBlobDecl
    ;

// VIEW declarations

viewDecl
    : ID VIEW LPAREN fieldRef RPAREN (COMMA viewAttr)* lineEnd
      viewSection*
      (END | DOT)
    ;

viewAttr
    : FILTERKW LPAREN expr RPAREN
    | ORDERKW  LPAREN expr RPAREN
    ;

viewSection
    : projectSection
    | joinSection
    ;

projectSection
    : PROJECTKW LPAREN projectList? RPAREN lineEnd
    ;

projectList
    : fieldRef (COMMA fieldRef)*
    ;

joinSection
    : JOINKW LPAREN fieldRef RPAREN lineEnd
      viewSection*
      (END | DOT)
    ;

// FILE KEY

fileKeyDecl
    : ID (KEYKW LPAREN keyFieldList RPAREN (COMMA keyAttr)*)? lineEnd
    ;

keyFieldList
    : keyField (COMMA keyField)*
    ;

keyField
    : (PLUS | MINUS)? fieldRef
    ;

keyAttr
    : ID (LPAREN argList? RPAREN)?
    ;

fileIndexDecl
    : ID (INDEXKW LPAREN argList? RPAREN)? lineEnd
    ;

fileMemoDecl
    : ID (MEMO LPAREN argList? RPAREN)? lineEnd
    ;

fileBlobDecl
    : ID (BLOB)? lineEnd
    ;

// INTERFACE

interfaceDecl
    : ID INTERFACE LPAREN fieldRef? RPAREN
      (COMMA TYPEKW)?
      (COMMA COMKW)?
      lineEnd
      interfaceMethod*
      (END | DOT)
    ;

interfaceMethod
    : prototypeDecl
    ;

// CLASS

classDecl
    : ID CLASSKW LPAREN fieldRef? RPAREN classAttrList? lineEnd
      classMember*
      (END | DOT)
    ;

classAttrList
    : COMMA classAttr (COMMA classAttr)*
    ;

classAttr
    : EXTERNAL
    | IMPLEMENTS
    | DLL LPAREN expr? RPAREN
    | STATIC
    | THREAD
    | BINDABLE
    | MODULE LPAREN expr? RPAREN
    | LINKKW LPAREN expr? RPAREN
    | TYPEKW
    | DIM LPAREN expr RPAREN
    | PARTIALKW
    ;

classMember
    : dataDecl
    | prototypeDecl
    ;

// KEYWORD construct

keywordDecl
    : ID? KEYWORDKW LPAREN keywordParamList RPAREN keywordAttr* lineEnd
    ;

keywordParamList
    : PIPE? expr (PIPE expr)* PIPE?
    ;

keywordAttr
    : ID LPAREN argList? RPAREN
    ;

// CODE and statements

codeSection
    : CODE lineEnd statement*
    ;

statement
    : QUESTION? coreStatement
    | lineEnd
    ;

coreStatement
    : assignStmt
    | procCallStmt
    | doStmt
    | ifStmt
    | caseStmt
    | executeStmt
    | loopStmt
    | acceptStmt
    | breakStmt
    | cycleStmt
    | exitStmt
    | routineStmt
    | routineDataBlock
    | codeMarkerStmt
    | includeStmt
    | returnStmt
    | openCloseStmt
    | lineFuncStmt
    | ellipseFuncStmt
    | imageFuncStmt
    | gotoStmt
    ;

// Assignments / calls

assignStmt
    : fieldRef (EQUAL | AMP_EQUAL | DEEP_ASSIGN | STAR_EQUAL | PLUS_EQUAL | DIV_EQUAL) expr lineEnd
    ;

procCallStmt
    : fieldRef LPAREN argList? RPAREN lineEnd
    ;

doStmt
    : DO fieldRef lineEnd
    ;

includeStmt
    : INCLUDEKW LPAREN expr (COMMA expr)? RPAREN (COMMA ONCEKW)? lineEnd
    ;

// EXECUTE

executeStmt
    : EXECUTE expr lineEnd
      executeBranch+
      executeElse?
      (END | DOT)
    ;

executeBranch
    : BEGIN lineEnd statement* (END | DOT)
    | statement
    ;

executeElse
    : ELSE lineEnd statement*
    ;

// IMAGE drawing function
imageFuncStmt
    : IMAGE LPAREN imageArgs RPAREN lineEnd
    ;

imageArgs
    : expr COMMA expr (COMMA expr)? (COMMA expr)? COMMA expr (COMMA argList)?
    ;

// IF

ifStmt
    : IF expr (THEN)? lineEnd
      statement*
      elsifClause*
      elseClause?
      (END | DOT)
    ;

elsifClause
    : ELSIF expr (THEN)? lineEnd
      statement*
    ;

elseClause
    : ELSE lineEnd
      statement*
    ;

// CASE

caseStmt
    : CASE expr lineEnd
      caseBranch*
      (ELSE lineEnd statement*)?
      (END | DOT)
    ;

caseBranch
    : OF caseLabel (OROF caseLabel)* lineEnd
      statement*
    ;

caseLabel
    : expr (TO expr)?
    ;

// LOOP

loopStmt
    : (ID)? LOOP loopHead? lineEnd
      statement*
      loopTail?
      (END | DOT)
    ;

loopHead
    : expr TIMES
    | ID EQUAL expr TO expr (BY expr)?
    | UNTIL expr
    | WHILE expr
    ;

loopTail
    : UNTIL expr
    | WHILE expr
    ;

// ACCEPT / BREAK / etc.

acceptStmt
    : ACCEPT lineEnd statement* (END | DOT)
    ;

breakStmt
    : BREAK (ID)? lineEnd
    ;

cycleStmt
    : CYCLE (ID)? lineEnd
    ;

exitStmt
    : EXIT lineEnd
    ;

routineStmt
    : ID ROUTINE lineEnd
    ;

routineDataBlock
    : DATAKW lineEnd
      declarationSection*
    ;

codeMarkerStmt
    : CODE lineEnd
    ;

returnStmt
    : RETURN expr? lineEnd
    ;

openCloseStmt
    : (OPEN | CLOSE) LPAREN fieldRef RPAREN lineEnd
    ;

// GOTO statement
gotoStmt
    : GOTO ID lineEnd
    ;

// DRAW / LINE function-style syntax
lineFuncStmt
    : LINE LPAREN lineCoordArgs RPAREN lineEnd
    ;

// ELLIPSE drawing function-style syntax
ellipseFuncStmt
    : ELLIPSE LPAREN lineCoordArgs RPAREN lineEnd
    ;

lineCoordArgs
    : expr COMMA expr COMMA expr COMMA expr (COMMA argList)?
    ;

// Expressions

expr
    : orExpr
    ;

orExpr
    : andExpr (OR andExpr)*
    ;

andExpr
    : equalityExpr (AND equalityExpr)*
    ;

equalityExpr
    : relationalExpr ((EQUAL | NEQ | AMP_EQUAL) relationalExpr)*
    ;

relationalExpr
    : additiveExpr ((LT | LTE | GT | GTE) additiveExpr)*
    ;

additiveExpr
    : multiplicativeExpr ((PLUS | MINUS | AMP) multiplicativeExpr)*
    ;

multiplicativeExpr
    : powExpr ((STAR | DIV | PERCENT) powExpr)*
    ;

powExpr
    : unaryExpr (CARET powExpr)?
    ;

unaryExpr
    : (NOT | TILDE | MINUS) unaryExpr
    | primary
    ;

primary
    : primaryBase
      ( LBRACE propertyParamList RBRACE
      | LBRACKET indexOrSlice RBRACKET
      )*
    ;

primaryBase
    : literal
    | fieldRef
    | ADDRESS LPAREN argList? RPAREN
    | LIKE LPAREN argList? RPAREN
    | POPUPKW LPAREN popupArgList RPAREN
    | LINKNAMEKW LPAREN argList? RPAREN
    | LINEWIDTHKW LPAREN argList? RPAREN
    | LPAREN expr RPAREN
    ;

popupArgList
    : expr (COMMA expr)? (COMMA expr)? (COMMA expr)?
    ;

indexOrSlice
    : expr
    | expr SLICE_COLON expr?
    | SLICE_COLON expr?
    ;

propertyParamList
    : expr (COMMA expr)*
    ;

literal
    : INTLIT
    | REALLIT
    | STRING
    | TRUE
    | FALSE
    | PICTURE
    | NULLKW
    ;

// Field references

fieldRef
    : ID (DOT ID)*
    ;

// Lexer rules

RECORD      : 'RECORD';
PROGRAM     : 'PROGRAM';
MAP         : 'MAP';
MODULE      : 'MODULE';
END         : 'END';
CODE        : 'CODE';
DATAKW      : 'DATA';

BYTE        : 'BYTE';
SHORT       : 'SHORT';
USHORT      : 'USHORT';
LONG        : 'LONG';
ULONG       : 'ULONG';
DECIMAL     : 'DECIMAL';
PDECIMAL    : 'PDECIMAL';
REAL        : 'REAL';
SREAL       : 'SREAL';
BFLOAT8     : 'BFLOAT8';
BFLOAT4     : 'BFLOAT4';
STRINGKW    : 'STRING';
CSTRING     : 'CSTRING';
BSTRING     : 'BSTRING';
PSTRING     : 'PSTRING';
USTRING     : 'USTRING';
BLOB        : 'BLOB';
MEMO        : 'MEMO';
DATE        : 'DATE';
TIME        : 'TIME';
BOOL        : 'BOOL';
QUEUE       : 'QUEUE';
VIEW        : 'VIEW';
WINDOW      : 'WINDOW';
FILE        : 'FILE';
GROUP       : 'GROUP';
VARIANT     : 'VARIANT';
ANY         : 'ANY';

PRE         : 'PRE';
USE         : 'USE';
LIKE        : 'LIKE';
DIM         : 'DIM';
OVER        : 'OVER';
STATIC      : 'STATIC';
PRIVATE     : 'PRIVATE';
THREAD      : 'THREAD';
AUTO        : 'AUTO';
BINARYKW    : 'BINARY';

BUTTON      : 'BUTTON';
LIST        : 'LIST';
ENTRY       : 'ENTRY';
BOX         : 'BOX';
PANEL       : 'PANEL';
REGION      : 'REGION';
LINE        : 'LINE';
SLIDER      : 'SLIDER';
SPIN        : 'SPIN';
ELLIPSE     : 'ELLIPSE';
IMAGE       : 'IMAGE';
OLE         : 'OLE';
PROMPTKW    : 'PROMPT';
RADIOKW     : 'RADIO';
SHEETKW     : 'SHEET';
TABKW       : 'TAB';
CHECKKW     : 'CHECK';
COMBOKW     : 'COMBO';
PROGRESS    : 'PROGRESS';

OPTIONKW    : 'OPTION';
BOXEDKW     : 'BOXED';
BEVELKW     : 'BEVEL';

PROC        : 'PROC';
ACCEPT      : 'ACCEPT';
CASE        : 'CASE';
OF          : 'OF';
OROF        : 'OROF';
ELSE        : 'ELSE';
ELSIF       : 'ELSIF';
IF          : 'IF';
THEN        : 'THEN';
LOOP        : 'LOOP';
BREAK       : 'BREAK';
CYCLE       : 'CYCLE';
EXIT        : 'EXIT';
GOTO        : 'GOTO';
ROUTINE     : 'ROUTINE';
RETURN      : 'RETURN';
OPEN        : 'OPEN';
CLOSE       : 'CLOSE';
DO          : 'DO';
EXECUTE     : 'EXECUTE';
BEGIN       : 'BEGIN';
TRUE        : 'TRUE';
FALSE       : 'FALSE';
AND         : 'AND';
OR          : 'OR';
NOT         : 'NOT';
TO          : 'TO';
ADDRESS     : 'ADDRESS';
EQUATE      : 'EQUATE';
TIMES       : 'TIMES';
WHILE       : 'WHILE';
UNTIL       : 'UNTIL';
BY          : 'BY';
INTERFACE   : 'INTERFACE';
TYPEKW      : 'TYPE';
COMKW       : 'COM';
CLASSKW     : 'CLASS';
EXTERNAL    : 'EXTERNAL';
IMPLEMENTS  : 'IMPLEMENTS';
DLL         : 'DLL';
BINDABLE    : 'BINDABLE';
LINKKW      : 'LINK';
PARTIALKW   : 'PARTIAL';
PROCEDUREKW : 'PROCEDURE';
ITEMIZEKW   : 'ITEMIZE';
INCLUDEKW   : 'INCLUDE';
ONCEKW      : 'ONCE';
KEYKW       : 'KEY';
INDEXKW     : 'INDEX';
NULLKW      : 'NULL';
KEYWORDKW   : 'KEYWORD';
PROTECTED   : 'PROTECTED';

MENUBAR     : 'MENUBAR';
TOOLBAR     : 'TOOLBAR';
MENU        : 'MENU';
ITEMKW      : 'ITEM';
STDKW       : 'STD';
RIGHTKW     : 'RIGHT';
DISABLEKW   : 'DISABLE';
LEFTKW      : 'LEFT';
HIDEKW      : 'HIDE';
FIRSTKW     : 'FIRST';
LASTKW      : 'LAST';
SEPARATORKW : 'SEPARATOR';
NOMERGEKW   : 'NOMERGE';
WALLPAPERKW : 'WALLPAPER';
POPUPKW     : 'POPUP';
LINKNAMEKW  : 'LINKNAME';
FULLKW      : 'FULL';
SCROLLKW    : 'SCROLL';
TRNKW       : 'TRN';
SKIPKW      : 'SKIP';
DEFAULTKW   : 'DEFAULT';
REQKW       : 'REQ';
TIPKW       : 'TIP';
FLATKW      : 'FLAT';
REPEATKW    : 'REPEAT';
DELAYKW     : 'DELAY';

REPORTKW    : 'REPORT';
ATKW        : 'AT';
FONTKW      : 'FONT';
COLORKW     : 'COLOR';

CENTER      : 'CENTER';
CENTERED    : 'CENTERED';
SYSTEMKW    : 'SYSTEM';
MAXKW       : 'MAX';
ICONKW      : 'ICON';
STATUSKW    : 'STATUS';
HLPKW       : 'HLP';
CURSORKW    : 'CURSOR';
MDI         : 'MDI';
MODAL       : 'MODAL';
MASK        : 'MASK';
GRAY        : 'GRAY';
TIMERKW     : 'TIMER';
ALRTKW      : 'ALRT';
ICONIZE     : 'ICONIZE';
MAXIMIZE    : 'MAXIMIZE';
MSGKW       : 'MSG';
PALETTEKW   : 'PALETTE';
DROPIDKW    : 'DROPID';
IMMKW       : 'IMM';
TOOLBOX     : 'TOOLBOX';
DOCKKW      : 'DOCK';
DOCKEDKW    : 'DOCKED';
LAYOUTKW    : 'LAYOUT';
TILED       : 'TILED';
HSCROLL     : 'HSCROLL';
VSCROLL     : 'VSCROLL';
NOFRAME     : 'NOFRAME';
HVSCROLL    : 'HVSCROLL';
RESIZEKW    : 'RESIZE';
DOUBLE      : 'DOUBLE';

FORMKW      : 'FORM';
HEADERKW    : 'HEADER';
DETAILKW    : 'DETAIL';
FOOTERKW    : 'FOOTER';
LANDSCAPEKW : 'LANDSCAPE';
PREVIEWKW   : 'PREVIEW';
PAPERKW     : 'PAPER';
THOUS       : 'THOUS';
MMKW        : 'MM';
POINTSKW    : 'POINTS';

PAGENOKW    : 'PAGENO';
EXTENDKW    : 'EXTEND';
CNTKW       : 'CNT';
SUMKW       : 'SUM';
AVEKW       : 'AVE';
MINKW       : 'MIN';
TALLYKW     : 'TALLY';
RESETKW     : 'RESET';
PAGEKW      : 'PAGE';
ANGLEKW     : 'ANGLE';
COMPATIBILITYKW : 'COMPATIBILITY';
FROMKW      : 'FROM';
FORMATKW    : 'FORMAT';
DROPKW      : 'DROP';
COLUMNKW    : 'COLUMN';
VCRKW       : 'VCR';
NOBARKW     : 'NOBAR';
GRIDKW      : 'GRID';
MARKKW      : 'MARK';
DRAGIDKW    : 'DRAGID';
PENKW       : 'PEN';
STYLEKW     : 'STYLE';
LINEWIDTHKW : 'LINEWIDTH';
READONLYKW  : 'READONLY';
INSKW       : 'INS';
UPRKW       : 'UPR';
OVRKW       : 'OVR';
CAPKW       : 'CAP';
FILLKW      : 'FILL';

WIZARDKW    : 'WIZARD';
SPREADKW    : 'SPREAD';
JOINKW      : 'JOIN';
NOSHEETKW   : 'NOSHEET';
UPKW        : 'UP';
DOWNKW      : 'DOWN';
ABOVEKW     : 'ABOVE';
BELOWKW     : 'BELOW';

FILTERKW    : 'FILTER';
ORDERKW     : 'ORDER';
PROJECTKW   : 'PROJECT';

LTE         : '<=';
GTE         : '>=';
NEQ         : '<>';
AMP_EQUAL   : '&=';
DEEP_ASSIGN : ':=:';
STAR_EQUAL  : '*=';
PLUS_EQUAL  : '+=';
DIV_EQUAL   : '/=';

SLICE_COLON : ':';

LT          : '<';
GT          : '>';
EQUAL       : '=';

CARET       : '^';
PLUS        : '+';
MINUS       : '-';
STAR        : '*';
DIV         : '/';
PERCENT     : '%';
TILDE       : '~';
AMP         : '&';
DOT         : '.';

LPAREN      : '(' ;
RPAREN      : ')' ;
LBRACE      : '{' ;
RBRACE      : '}' ;
LBRACKET    : '[' ;
RBRACKET    : ']' ;
COMMA       : ',' ;

QUESTION    : '?';
PIPE        : '|';

INTLIT      : [0-9]+ ;
REALLIT     : [0-9]+ '.' [0-9]+ ;

// STRING literal with proper escaping
STRING
    : '\'' (ESC | ~['\\])* '\''
    ;

fragment ESC
    : '\\' .
    ;

PICTURE
    : '@' ~[ \t\r\n,;(){}[\]]+
    ;

EOL
    : [\r\n]+
    ;

NEWLINE
    : ';'
    ;

ID
    : ID_START ID_PART* ('#' | '$' | '"')?
    ;

fragment ID_START : [a-z_];
fragment ID_PART  : [a-z0-9_:$];

LINE_CONTINUATION
    : '|' [ \t]* [\r\n]+ -> skip
    ;

LINE_COMMENT
    : '!' ~[\r\n]* -> skip
    ;

WS
    : [ \t\f]+ -> skip
    ;

Thank you, Mr. Carl for the pointer to the testing framework ANTLR Lab
You can actually post the whole file on one side without splitting it out.

Thanks for figuring out how put the spec all in one tab to make the test easier!

When I paste in this Class as would be in an INC file:

ConstantClass   CLASS,TYPE,MODULE('ABUTIL.CLW'),LINK('ABUTIL.CLW',_ABCLinkMode_),DLL(_ABCDllMode_)
CharPnt           LONG,PRIVATE
Next              PROCEDURE(FILE F)
                END

The 2nd error 2:65 missing ')' at ',' wants Parens () after “Class” and not just a comma e.g. CLASS,TYPE.
The fix is to make the (fieldRef) optional with ()?
Before : ID CLASSKW LPAREN fieldRef? RPAREN classAttrList? lineEnd
Fixed : ID CLASSKW (LPAREN fieldRef? RPAREN)? classAttrList? lineEnd


After fixing the above it did not like the ,_ABCLinkMode_ in
LINK('ABUTIL.CLW',_ABCLinkMode_)
In classAttr there’s the LINK line
| LINKKW LPAREN expr? RPAREN
that does not allow a comma and second attribute ('file',_abc_).

It worked to add an optional “, ID” as
| LINKKW LPAREN expr? (COMMA ID)? RPAREN

Edit:
Link can have a number Link(,1) so change ID to expr?
| LINKKW LPAREN expr? (COMMA expr?)? RPAREN


After fixing LINK(,_id_) above then the error 4:18 no viable alternative at input 'Next PROCEDURE'
on the line Next PROCEDURE(FILE F)
I think Mark pointed out there is nothing to allow the format starting in column 1 of Name Procedure(parms).


The 1st error 1:0 missing 'PROGRAM' at 'ConstantClass'
makes me think the spec always wants “PROGRAM” first, but you can have a Class .INC / .CLW file that does not. Or a Member MODULE, or Equates, or code snippet.

To fix maybe add ? after programHeader to make it 1 or 0 times
Yes! No more error after adding ? so : programHeader?

program
    : programHeader?   //<--- Add ? on End -----------
      lineEnd*               // allow blank lines after PROGRAM
      mapSection?
      (lineEnd | declarationSection)*  // allow interleaved blank lines and declarations
      codeSection
      lineEnd*               // allow trailing blank lines
      EOF
    ;

programHeader
    : PROGRAM
    ;

Re mapSection? there can be multiple MAP’s so change ? to * = mapSection*
Those can be mixed with Data declartions so maybe (group)* MAP and Data:

program
    : programHeader?   //<--- Add ? on End so PROGRAM is optional -------
      lineEnd*         // allow blank lines after PROGRAM
      (                // Group (MAP + DATA)* to allow multiple MAPs mixed with Data
        mapSection*    //change ? to * to allow multiple MAPs
        (lineEnd | declarationSection)*  // allow interleaved blank lines and declarations
      )*               // Group (MAP + DATA)* 
      codeSection

FYI in the very first post at the bottom I added a few syntax rules about ANTLR.

1 Like

TBH I am not sure if this is useful or not, but for comparison I asked Claude to do the same (ie. create ANTLR4 definition for the Clarion programming language).

He/It has done things a bit differently in places so if there is anything “better” here it might be worth considering mixing and matching (merging) parts.

Claude said:

I’ve created an ANTLR4 grammar for the Clarion programming language. This grammar covers the major features of Clarion including:

Key Features Included:

  • MAP sections - for declaring external procedures and modules
  • Data declarations - BYTE, SHORT, LONG, STRING, CSTRING, DECIMAL, etc.
  • Complex structures - GROUP, QUEUE, RECORD, CLASS, INTERFACE
  • Procedures - with parameters and return types
  • Control flow - IF/THEN/ELSE, CASE/OF, LOOP, EXECUTE
  • File I/O - OPEN, CLOSE, SET, GET, ADD, PUT, DELETE
  • Expressions - arithmetic, logical, relational operators
  • String literals - single-quoted with escape sequences
  • Comments - exclamation mark style (!)
  • Case-insensitive keywords - using fragment rules

The grammar is designed to be case-insensitive for keywords (as Clarion is case-insensitive) and supports the main syntactic structures you’d find in typical Clarion programs. You may need to extend or modify it based on specific Clarion dialects or advanced features you’re working with.

anyway this is what it came up with:

grammar Clarion;

// Parser Rules

program
    : (section)* EOF
    ;

section
    : mapSection
    | memberSection
    | procedureSection
    | dataSection
    | codeSection
    ;

mapSection
    : MAP mapItem* END
    ;

mapItem
    : MODULE LPAREN STRING RPAREN moduleItem* END
    | procedurePrototype
    ;

moduleItem
    : procedurePrototype
    ;

procedurePrototype
    : IDENTIFIER LPAREN parameterList? RPAREN (COMMA dataType)?
    ;

memberSection
    : IDENTIFIER GROUP (COMMA attributes)? memberItem* END
    ;

memberItem
    : dataDeclaration
    ;

procedureSection
    : IDENTIFIER PROCEDURE (LPAREN parameterList? RPAREN)? (COMMA dataType)?
    ;

dataSection
    : (dataDeclaration | recordDeclaration)*
    ;

dataDeclaration
    : IDENTIFIER (dataType | groupDeclaration | queueDeclaration) (COMMA attributes)?
    ;

groupDeclaration
    : GROUP (COMMA PRE LPAREN IDENTIFIER RPAREN)? (COMMA attributes)? groupItem* END
    ;

groupItem
    : dataDeclaration
    ;

queueDeclaration
    : QUEUE (COMMA PRE LPAREN IDENTIFIER RPAREN)? (COMMA attributes)? queueItem* END
    ;

queueItem
    : dataDeclaration
    ;

recordDeclaration
    : IDENTIFIER RECORD (COMMA PRE LPAREN IDENTIFIER RPAREN)? (COMMA attributes)? recordItem* END
    ;

recordItem
    : dataDeclaration
    ;

dataType
    : BYTE
    | SHORT
    | USHORT
    | LONG
    | ULONG
    | REAL
    | SREAL
    | DECIMAL LPAREN NUMBER (COMMA NUMBER)? RPAREN
    | PDECIMAL LPAREN NUMBER (COMMA NUMBER)? RPAREN
    | STRING LPAREN NUMBER RPAREN
    | CSTRING LPAREN NUMBER RPAREN
    | PSTRING LPAREN NUMBER RPAREN
    | BSTRING LPAREN NUMBER RPAREN
    | ANY
    | WINDOW
    | BUTTON
    | ENTRY
    | LIST
    | TEXT
    | GROUP
    | QUEUE
    | FILE
    | KEY
    | MEMO
    | BLOB
    | CLASS
    | INTERFACE
    | LIKE LPAREN IDENTIFIER RPAREN
    | AMPERSAND dataType
    ;

attributes
    : attribute (COMMA attribute)*
    ;

attribute
    : IDENTIFIER (LPAREN attributeValue (COMMA attributeValue)* RPAREN)?
    | NAME LPAREN STRING RPAREN
    | PRE LPAREN IDENTIFIER RPAREN
    | DIM LPAREN NUMBER (COMMA NUMBER)* RPAREN
    | OVER LPAREN IDENTIFIER RPAREN
    | EXTERNAL
    | STATIC
    | AUTO
    | THREAD
    | DLL
    ;

attributeValue
    : STRING
    | NUMBER
    | IDENTIFIER
    ;

parameterList
    : parameter (COMMA parameter)*
    ;

parameter
    : IDENTIFIER dataType
    | ASTERISK dataType
    ;

codeSection
    : CODE statement* END?
    ;

statement
    : assignment
    | ifStatement
    | caseStatement
    | loopStatement
    | ofStatement
    | executeStatement
    | exitStatement
    | breakStatement
    | cycleStatement
    | returnStatement
    | procedureCall
    | doStatement
    | freeStatement
    | openStatement
    | closeStatement
    | setStatement
    | getStatement
    | addStatement
    | putStatement
    | deleteStatement
    | clearStatement
    | startStatement
    | acceptStatement
    | displayStatement
    | printStatement
    | label
    ;

assignment
    : expression ASSIGN expression
    ;

ifStatement
    : IF expression (THEN)? statement* (ELSE statement*)? (END | DOT)?
    ;

caseStatement
    : CASE expression (OF statement*)* (ELSE statement*)? END
    ;

loopStatement
    : LOOP (NUMBER TIMES)? statement* END
    ;

ofStatement
    : OF expression statement*
    ;

executeStatement
    : EXECUTE expression statement*
    ;

exitStatement
    : EXIT
    ;

breakStatement
    : BREAK (IDENTIFIER)?
    ;

cycleStatement
    : CYCLE (IDENTIFIER)?
    ;

returnStatement
    : RETURN (expression)?
    ;

procedureCall
    : IDENTIFIER LPAREN argumentList? RPAREN
    | IDENTIFIER
    ;

doStatement
    : DO IDENTIFIER (TO IDENTIFIER)?
    ;

freeStatement
    : FREE LPAREN IDENTIFIER RPAREN
    ;

openStatement
    : OPEN LPAREN IDENTIFIER RPAREN
    ;

closeStatement
    : CLOSE LPAREN IDENTIFIER RPAREN
    ;

setStatement
    : SET LPAREN IDENTIFIER (COMMA IDENTIFIER)? RPAREN
    ;

getStatement
    : GET LPAREN IDENTIFIER (COMMA IDENTIFIER)? RPAREN
    ;

addStatement
    : ADD LPAREN IDENTIFIER (COMMA IDENTIFIER)? RPAREN
    ;

putStatement
    : PUT LPAREN IDENTIFIER RPAREN
    ;

deleteStatement
    : DELETE LPAREN IDENTIFIER RPAREN
    ;

clearStatement
    : CLEAR LPAREN IDENTIFIER (COMMA IDENTIFIER)? RPAREN
    ;

startStatement
    : START LPAREN IDENTIFIER (COMMA IDENTIFIER)? RPAREN
    ;

acceptStatement
    : ACCEPT
    ;

displayStatement
    : DISPLAY (LPAREN RPAREN)?
    ;

printStatement
    : PRINT LPAREN expression RPAREN
    ;

label
    : IDENTIFIER COLON
    ;

argumentList
    : expression (COMMA expression)*
    ;

expression
    : primary
    | expression LPAREN argumentList? RPAREN
    | expression LBRACK expression RBRACK
    | expression DOT IDENTIFIER
    | expression AMPERSAND IDENTIFIER
    | AMPERSAND expression
    | NOT expression
    | MINUS expression
    | expression (TIMES | DIVIDE | MODULO) expression
    | expression (PLUS | MINUS) expression
    | expression (LT | LE | GT | GE | EQ | NE) expression
    | expression AND expression
    | expression OR expression
    ;

primary
    : NUMBER
    | STRING
    | IDENTIFIER
    | LPAREN expression RPAREN
    | TRUE
    | FALSE
    ;

// Lexer Rules

// Keywords
MAP         : M A P ;
MODULE      : M O D U L E ;
PROCEDURE   : P R O C E D U R E ;
CODE        : C O D E ;
END         : E N D ;
IF          : I F ;
THEN        : T H E N ;
ELSE        : E L S E ;
CASE        : C A S E ;
OF          : O F ;
LOOP        : L O O P ;
TIMES       : T I M E S ;
EXECUTE     : E X E C U T E ;
EXIT        : E X I T ;
BREAK       : B R E A K ;
CYCLE       : C Y C L E ;
RETURN      : R E T U R N ;
DO          : D O ;
TO          : T O ;
FREE        : F R E E ;
OPEN        : O P E N ;
CLOSE       : C L O S E ;
SET         : S E T ;
GET         : G E T ;
ADD         : A D D ;
PUT         : P U T ;
DELETE      : D E L E T E ;
CLEAR       : C L E A R ;
START       : S T A R T ;
ACCEPT      : A C C E P T ;
DISPLAY     : D I S P L A Y ;
PRINT       : P R I N T ;
AND         : A N D ;
OR          : O R ;
NOT         : N O T ;
TRUE        : T R U E ;
FALSE       : F A L S E ;
LIKE        : L I K E ;
OVER        : O V E R ;
EXTERNAL    : E X T E R N A L ;
STATIC      : S T A T I C ;
AUTO        : A U T O ;
THREAD      : T H R E A D ;
DLL         : D L L ;
PRE         : P R E ;
NAME        : N A M E ;
DIM         : D I M ;

// Data Types
BYTE        : B Y T E ;
SHORT       : S H O R T ;
USHORT      : U S H O R T ;
LONG        : L O N G ;
ULONG       : U L O N G ;
REAL        : R E A L ;
SREAL       : S R E A L ;
DECIMAL     : D E C I M A L ;
PDECIMAL    : P D E C I M A L ;
STRING      : S T R I N G ;
CSTRING     : C S T R I N G ;
PSTRING     : P S T R I N G ;
BSTRING     : B S T R I N G ;
ANY         : A N Y ;
WINDOW      : W I N D O W ;
BUTTON      : B U T T O N ;
ENTRY       : E N T R Y ;
LIST        : L I S T ;
TEXT        : T E X T ;
GROUP       : G R O U P ;
QUEUE       : Q U E U E ;
FILE        : F I L E ;
KEY         : K E Y ;
MEMO        : M E M O ;
BLOB        : B L O B ;
CLASS       : C L A S S ;
INTERFACE   : I N T E R F A C E ;
RECORD      : R E C O R D ;

// Operators
ASSIGN      : '=' ;
PLUS        : '+' ;
MINUS       : '-' ;
TIMES       : '*' ;
DIVIDE      : '/' ;
MODULO      : '%' ;
LT          : '<' ;
LE          : '<=' ;
GT          : '>' ;
GE          : '>=' ;
EQ          : '==' ;
NE          : '~=' | '<>' ;
AMPERSAND   : '&' ;
ASTERISK    : '*' ;

// Punctuation
LPAREN      : '(' ;
RPAREN      : ')' ;
LBRACK      : '[' ;
RBRACK      : ']' ;
COMMA       : ',' ;
DOT         : '.' ;
COLON       : ':' ;
SEMICOLON   : ';' ;
PIPE        : '|' ;

// Literals
NUMBER
    : [0-9]+ ('.' [0-9]+)?
    ;

IDENTIFIER
    : [a-zA-Z_][a-zA-Z0-9_]*
    ;

STRING
    : '\'' ( ~'\'' | '\'\'' )* '\''
    ;

// Whitespace and Comments
WS
    : [ \t\r\n]+ -> skip
    ;

COMMENT
    : '!' ~[\r\n]* -> skip
    ;

// Case-insensitive fragment helpers
fragment A : [aA] ;
fragment B : [bB] ;
fragment C : [cC] ;
fragment D : [dD] ;
fragment E : [eE] ;
fragment F : [fF] ;
fragment G : [gG] ;
fragment H : [hH] ;
fragment I : [iI] ;
fragment J : [jJ] ;
fragment K : [kK] ;
fragment L : [lL] ;
fragment M : [mM] ;
fragment N : [nN] ;
fragment O : [oO] ;
fragment P : [pP] ;
fragment Q : [qQ] ;
fragment R : [rR] ;
fragment S : [sS] ;
fragment T : [tT] ;
fragment U : [uU] ;
fragment V : [vV] ;
fragment W : [wW] ;
fragment X : [xX] ;
fragment Y : [yY] ;
fragment Z : [zZ] ;

it occurred to me that I could just ask Claude to do this so gave “him” the ChatGPT version and “he” said he would

  • Compare the two grammars side-by-side
  • Identify the strengths and unique features of each
  • Create a merged version that incorporates the best elements from both
  • Highlight what improvements were made in the final version

after doing that “he” said:

Perfect! I’ve created a comprehensive merged ANTLR4 grammar that combines the best elements from both versions. Here’s what I incorporated:

Key Improvements from the Merge:

From ChatGPT’s Grammar:

  1. :white_check_mark: options { caseInsensitive = true; } - Much cleaner than using fragments
  2. :white_check_mark: Better program structure - Allows blank lines and more flexible ordering
  3. :white_check_mark: Comprehensive WINDOW/REPORT/MENU support - Very detailed control declarations
  4. :white_check_mark: SHEET with nested TABs - Proper hierarchical structure
  5. :white_check_mark: OPTION control with nested controls
  6. :white_check_mark: OLE control with optional MENUBAR
  7. :white_check_mark: VIEW declarations with PROJECT/JOIN sections
  8. :white_check_mark: INTERFACE and CLASS declarations
  9. :white_check_mark: ITEMIZE, KEYWORD constructs
  10. :white_check_mark: Expression slicing (array[1:5])
  11. :white_check_mark: Property indexing (object{prop})
  12. :white_check_mark: Multiple assignment operators (:=:, &=, *=, +=, /=)
  13. :white_check_mark: ELSIF clause support
  14. :white_check_mark: ROUTINE and DATA blocks
  15. :white_check_mark: LINE/ELLIPSE/IMAGE drawing functions
  16. :white_check_mark: Better PICTURE token handling

From My Original Grammar:

  1. :white_check_mark: Simpler overall structure - Good foundation
  2. :white_check_mark: File operations - OPEN, CLOSE, GET, SET, etc.
  3. :white_check_mark: Basic expression handling

Additional Enhancements:

  • :white_check_mark: More complete attribute lists for controls
  • :white_check_mark: Better handling of optional parameters
  • :white_check_mark: Support for reference types (&STRING, &QUEUE, etc.)
  • :white_check_mark: Comprehensive report sections (FORM, HEADER, DETAIL, BREAK, FOOTER)
  • :white_check_mark: Full menu/menubar/toolbar support
  • :white_check_mark: FILE attributes (DRIVER, CREATE, OWNER, ENCRYPT, RECLAIM)
  • :white_check_mark: Better expression precedence
  • :white_check_mark: Line continuation support (|)

The merged grammar is now production-ready and covers virtually all major Clarion language constructs including data declarations, procedures, classes, interfaces, windows, reports, and comprehensive control flow statements!

Claude can make mistakes. Please double-check responses.

I suspect the “production-ready” claim is highly optimistic. Anyway here is the resultant grammar:

https://claude.ai/public/artifacts/be136f10-e50c-47e4-8dd8-68672996c5fd

Thank you for the feedback. I give this a try with the test file I am using.

Your claude Clarion grammar looks a bit cleaner as a starting point. There are some things that I have already solved and some of those solutions looks a little odd and ChatGPT gives some interesting advice

The Grammar that I am current working on is testing a large window declarion from something that I did not create. It is a learning experience including dealing with INTLIT in hex, binary, and octal formats. When I get past a complete test with everything functional I will repost the grammar and test file.

I think you are correct. This task might take some more colaboration to get all the Clarion parts working. Thank you for your example Clarion language grammar.

1 Like

Greetings - Enclosed is the lattest grammar and the clarion window definition that I used to test it. This got completed before I got your language file. But I did save your original example to try at a later time. Good times.
Regards

grammar ClarionGrammar;

options { caseInsensitive = true; }

// Parser rules

program
    : programHeader? lineEnd*
      mapSection?
      declarationSection*
      codeSection?
      procedureDecl*
      EOF
    ;

// PROGRAM or MEMBER header
programHeader
    : PROGRAM                                 #programHeaderProgram
    | MEMBER LPAREN expr? RPAREN              #programHeaderMember
    ;

lineEnd
    : EOL
    | NEWLINE
    ;

// MAP section

mapSection
    : MAP lineEnd*
      (mapEntry lineEnd*)*
      (END | DOT)
    ;

mapEntry
    : moduleDecl
    | prototypeDecl
    ;

moduleDecl
    : MODULE LPAREN expr? RPAREN lineEnd?
      prototypeDecl*
      (END | DOT)
    ;

// MAP prototypes

prototypeDecl
    : ID LPAREN prototypeParamList? RPAREN (COMMA returnType)? (COMMA PROC)? lineEnd?
    ;

prototypeParamList
    : prototypeParam (COMMA prototypeParam)*
    ;

prototypeParam
    : ( STAR typeSpec
      | typeSpec
      | LT STAR typeSpec GT
      | LT typeSpec GT
      )
      (EQUAL expr)?
    ;

// Types

// Base primitive/builtin types (no refs, no IDs, no QUESTION)
primitiveType
    : BYTE
    | SHORT
    | USHORT
    | LONG
    | ULONG
    | DECIMAL
    | PDECIMAL
    | REAL
    | SREAL
    | BFLOAT8
    | BFLOAT4
    | STRINGKW
    | CSTRING
    | BSTRING
    | PSTRING
    | USTRING
    | BLOB
    | MEMO
    | DATE
    | TIME
    | BOOL
    | GROUP
    | QUEUE
    | FILE
    | VIEW
    | VARIANT
    | ANY
    ;

// Types
typeSpec
    : primitiveType
    | refType
    | ID
    | QUESTION   // allow ? as a parameter type
    ;

// Reference types: &BYTE, &STRING, &QUEUE, &FILE, &VIEW, &WINDOW, etc.
refType
    : AMP (
          BYTE
        | SHORT
        | USHORT
        | LONG
        | ULONG
        | DATE
        | TIME
        | REAL
        | SREAL
        | BFLOAT8
        | BFLOAT4
        | DECIMAL
        | PDECIMAL
        | STRINGKW
        | CSTRING
        | PSTRING
        | GROUP
        | QUEUE
        | FILE
        | KEYKW
        | BLOB
        | VIEW
        | WINDOW
        | USTRING
        | BSTRING
        | VARIANT
      )
    ;

builtinType
    : primitiveType
    ;

// Data type arguments and STRING/DECIMAL/PDECIMAL syntax

dataLikeOrType
    : LIKE LPAREN fieldRef RPAREN
    | STRINGKW stringTypeArgs?
    | typeSpec typeArgs?
    ;

// Simplified to reduce ambiguities: any arg list in parens
typeArgs
    : LPAREN argList? RPAREN
    ;

// STRING( string-constant | length-expr | picture )
stringTypeArgs
    : LPAREN stringArg RPAREN
    ;

stringArg
    : STRING        // string constant
    | PICTURE       // picture like @s10, @n3
    | expr          // length expression
    ;

// Procedure parameter lists (for PROCEDURE declarations)

procedureProtoParamList
    : procedureProtoParam (COMMA procedureProtoParam)*
    ;

procedureProtoParam
    : typeSpec (ID)? (EQUAL expr)?
    ;

// Declarations

declarationSection
    : windowDecl
    | applicationDecl
    | queueDecl
    | reportDecl
    | procedureDecl
    | labelDecl
    | itemizeDecl
    | recordDecl
    | groupDecl
    | fileDecl
    | viewDecl
    | interfaceDecl
    | classDecl
    | keywordDecl
    | dataDecl
    | topLevelControlDecl
    | lineEnd      // allow and ignore blank lines at declaration level
    ;

// DATA

dataDecl
    : ID dataLikeOrType? (COMMA dataAttr)* lineEnd
    ;

// LIKE-only declaration: LIKE(likeDeclaration) [,DIM()] [,OVER()] [,PRE()] [,NAME()] [,EXTERNAL] [,DLL] [,STATIC] [,THREAD] [,BINDABLE]
likeNewDecl
    : LIKE LPAREN fieldRef RPAREN (COMMA dataAttr)* lineEnd
    ;

argList
    : expr (COMMA expr)*
    ;

nullArgList
    : nullArg (COMMA nullArg)*
    ;

nullArg
    : expr?
    ;

atArgs
    : atSlot
    | atSlot COMMA atSlot
    | atSlot COMMA atSlot COMMA atSlot
    | atSlot COMMA atSlot COMMA atSlot COMMA atSlot
    ;

atSlot
    : expr?
    ;

bevelArgs
    : bevelSlot
    | bevelSlot COMMA bevelSlot
    | bevelSlot COMMA bevelSlot COMMA bevelSlot
    ;

bevelSlot
    : expr?
    ;

fontArgList
    : fontArg
    | fontArg COMMA fontArg
    | fontArg COMMA fontArg COMMA fontArg
    | fontArg COMMA fontArg COMMA fontArg COMMA fontArg
    | fontArg COMMA fontArg COMMA fontArg COMMA fontArg COMMA fontArg
    ;

fontArg
    : expr?
    ;

dataAttr
    : PRE LPAREN ID RPAREN
    | USE LPAREN fieldRef RPAREN
    | DIM LPAREN expr (COMMA expr)* RPAREN
    | OVER LPAREN fieldRef RPAREN
    | STATIC
    | PRIVATE
    | THREAD
    | AUTO
    | BINARYKW
    | EXTERNAL
    | DLL LPAREN argList? RPAREN
    | PROTECTED
    | ID
    | ID LPAREN argList? RPAREN
    ;

// QUEUE

queueDecl
    : ID QUEUE queueTypeArgs? (COMMA queueAttr)* lineEnd
      queueFieldDecl+
      (END | DOT)
    ;

queueTypeArgs
    : LPAREN fieldRef? RPAREN
    ;

queueAttr
    : PRE (LPAREN ID RPAREN)?
    | STATIC
    | THREAD
    | TYPEKW
    | BINDABLE
    | EXTERNAL
    | DLL (LPAREN argList? RPAREN)?
    | ID
    | ID LPAREN argList? RPAREN
    ;

queueFieldDecl
    : ID dataLikeOrType? (COMMA dataAttr)* lineEnd
    ;

// WINDOW

windowDecl
    : (ID | WINDOW) WINDOW windowArgs? lineEnd*
      windowMenuBarSection?
      windowToolBarSection?
      (windowControlDecl | lineEnd)*
      (END | DOT)
    ;

applicationDecl
    : ID APPLICATION LPAREN argList? RPAREN
      (COMMA applicationAttr)* lineEnd
      windowMenuBarSection?
      windowToolBarSection?
      END
    ;

applicationAttr
    : ATKW      LPAREN RPAREN
    | ATKW      LPAREN atArgs RPAREN
    | FONTKW    LPAREN RPAREN
    | FONTKW    LPAREN fontArgList RPAREN
    | ICONKW    LPAREN argList? RPAREN
    | STATUSKW  LPAREN argList? RPAREN
    | HLPKW     LPAREN argList? RPAREN
    | CURSORKW  LPAREN argList? RPAREN
    | TIMERKW   LPAREN argList? RPAREN
    | ALRTKW    LPAREN argList? RPAREN
    | MSGKW     LPAREN argList? RPAREN
    | PALETTEKW LPAREN argList? RPAREN
    | LAYOUTKW  
    | LAYOUTKW  LPAREN argList? RPAREN
    | WALLPAPERKW LPAREN RPAREN
    | WALLPAPERKW LPAREN nullArgList RPAREN
    | CENTER
    | CENTERED
    | SYSTEMKW
    | MAXKW
    | ICONIZE
    | MAXIMIZE
    | MASK
    | IMMKW
    | AUTO
    | TILED
    | HSCROLL
    | VSCROLL
    | NOFRAME
    | HVSCROLL
    | RESIZEKW
    ;

windowArgs
    : LPAREN argList? RPAREN (COMMA windowAttr)*
    ;

windowAttr
    : ATKW      LPAREN RPAREN
    | ATKW      LPAREN atArgs RPAREN
    | FONTKW    LPAREN RPAREN
    | FONTKW    LPAREN fontArgList RPAREN
    | ICONKW    LPAREN argList? RPAREN
    | STATUSKW  LPAREN argList? RPAREN
    | HLPKW     LPAREN argList? RPAREN
    | CURSORKW  LPAREN argList? RPAREN
    | TIMERKW   LPAREN argList? RPAREN
    | ALRTKW    LPAREN argList? RPAREN
    | MSGKW     LPAREN argList? RPAREN
    | PALETTEKW LPAREN argList? RPAREN
    | DROPIDKW  LPAREN argList? RPAREN
    | DOCKKW    LPAREN argList? RPAREN
    | DOCKEDKW  LPAREN argList? RPAREN
    | LAYOUTKW
    | LAYOUTKW  LPAREN argList? RPAREN
    | COLORKW   LPAREN argList? RPAREN
    | WALLPAPERKW LPAREN RPAREN
    | WALLPAPERKW LPAREN nullArgList RPAREN
    | CENTER
    | CENTERED
    | SYSTEMKW
    | MAXKW
    | MDI
    | MODAL
    | MASK
    | GRAY
    | ICONIZE
    | MAXIMIZE
    | IMMKW
    | AUTO
    | TOOLBOX
    | TILED
    | HSCROLL
    | VSCROLL
    | NOFRAME
    | HVSCROLL
    | RESIZEKW
    | DOUBLE
    | ID
    | ID LPAREN argList? RPAREN
    ;

// MENUBAR / MENU / ITEM

windowMenuBarSection
    : MENUBAR menubarArgs? lineEnd
      (menuBarEntry | lineEnd)*
      (END | DOT)
    ;

menubarArgs
    : (COMMA menubarAttr)+
    ;

menubarAttr
    : USE LPAREN argList? RPAREN
    | NOMERGEKW
    ;

menuBarEntry
    : menuDecl
    | menuItemDecl
    | windowMenuDecl
    ;

menuDecl
    : MENU (LPAREN argList? RPAREN)? menuArgs? lineEnd
      (menuEntry | lineEnd)*
      (END | DOT)
    ;

menuArgs
    : (COMMA menuAttr)+
    ;

menuAttr
    : ATKW      LPAREN atArgs RPAREN
    | USE       LPAREN argList? RPAREN
    | KEYKW     LPAREN argList? RPAREN
    | MSGKW     LPAREN argList? RPAREN
    | HLPKW     LPAREN argList? RPAREN
    | STDKW
    | STDKW     LPAREN argList? RPAREN
    | RIGHTKW
    | DISABLEKW
    | COLORKW
    | COLORKW   LPAREN argList? RPAREN
    | LEFTKW    LPAREN argList? RPAREN
    | HIDEKW
    | ICONKW    LPAREN argList? RPAREN
    | FONTKW    LPAREN argList? RPAREN
    | FIRSTKW
    | LASTKW
    ;

menuEntry
    : menuItemDecl
    | menuDecl
    ;

menuItemDecl
    : ITEMKW (LPAREN argList? RPAREN)? itemArgs? lineEnd
    ;

itemArgs
    : (COMMA itemAttr)+
    ;

itemAttr
    : ATKW      LPAREN atArgs RPAREN
    | USE       LPAREN argList? RPAREN
    | KEYKW     LPAREN argList? RPAREN
    | MSGKW     LPAREN argList? RPAREN
    | HLPKW     LPAREN argList? RPAREN
    | STDKW
    | STDKW     LPAREN argList? RPAREN
    | CHECKKW
    | DISABLEKW
    | COLORKW
    | LEFTKW    LPAREN argList? RPAREN
    | HIDEKW
    | SEPARATORKW
    | ICONKW    LPAREN argList? RPAREN
    | FONTKW    LPAREN argList? RPAREN
    | FIRSTKW
    | LASTKW
    ;

windowMenuDecl
    : ID (LPAREN argList? RPAREN)?
      (COMMA ID (LPAREN argList? RPAREN)?)* lineEnd
    ;

// TOOLBAR

windowToolBarSection
    : TOOLBAR toolbarArgs? lineEnd
      windowControlDecl*
      (END | DOT)
    ;

toolbarArgs
    : (COMMA toolbarAttr)+
    ;

toolbarAttr
    : ATKW      LPAREN RPAREN
    | ATKW      LPAREN atArgs RPAREN
    | USE       LPAREN argList? RPAREN
    | CURSORKW  LPAREN argList? RPAREN
    | FONTKW    LPAREN RPAREN
    | FONTKW    LPAREN fontArgList RPAREN
    | NOMERGEKW
    | COLORKW
    | LAYOUTKW  
    | LAYOUTKW  LPAREN argList? RPAREN
    | WALLPAPERKW LPAREN RPAREN
    | WALLPAPERKW LPAREN nullArgList RPAREN
    | TILED
    | CENTERED
    ;

// Top-level stray controls (IMAGE/TEXT/PROMPT/etc.) to be tolerant of legacy code
topLevelControlDecl
    : ID? controlType (LPAREN argList? RPAREN)? controlAttrs lineEnd
    ;

// Controls (WINDOW)

windowControlDecl
    : oleControlDecl           // OLE with optional MENUBAR & nested items
    | optionControlDecl        // OPTION with nested child controls
    | groupControlDecl         // GROUP with nested controls
    | sheetControlDecl         // SHEET with nested TABs
    | listControlDecl          // LIST with specialized attrs
    | lineControlDecl          // LINE with specialized attrs
    // controls with explicit argument lists
    | ID? IMAGE    LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? PROMPTKW LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? TEXTKW   (LPAREN argList? RPAREN)? controlAttrs lineEnd
    // generic single-line controls (BUTTON, ENTRY, STRING, BOX, REGION, PANEL, etc.)
    | ID? controlType (LPAREN argList? RPAREN)? controlAttrs lineEnd
    ;

// OPTION control with nested child controls (RADIO etc.)
optionControlDecl
    : ID? OPTIONKW LPAREN argList? RPAREN controlAttrs lineEnd
      (windowControlDecl | lineEnd)*
      (END | DOT)
    ;

// GROUP control with nested child controls
groupControlDecl
    : ID? GROUP controlAttrs lineEnd
      windowControlDecl*
      (END | DOT)
    ;

// Special OLE control with optional nested MENUBAR and END
oleControlDecl
    : ID? OLE oleControlAttrs lineEnd
      oleMenuBarSection?
      (END | DOT)
    ;

oleControlAttrs
    : COMMA ATKW      LPAREN atArgs RPAREN (COMMA controlAttr)*
    ;

oleMenuBarSection
    : MENUBAR menubarArgs? lineEnd
      menuBarEntry*
      (END | DOT)
    ;

listControlDecl
    : ID? LIST listControlAttrs lineEnd
    ;

listControlAttrs
    : COMMA ATKW      LPAREN atArgs RPAREN (COMMA controlAttr)*
    ;

lineControlDecl
    : ID? LINE lineControlAttrs lineEnd
    ;

lineControlAttrs
    : COMMA ATKW      LPAREN atArgs RPAREN (COMMA controlAttr)*
    ;

// SHEET control with nested TABs
sheetControlDecl
    : ID? SHEETKW sheetControlAttrs lineEnd
      sheetTabDecl+
      (END | DOT)
    ;

sheetControlAttrs
    : COMMA sheetControlAttr (COMMA sheetControlAttr)*
    ;

sheetControlAttr
    : ATKW      LPAREN RPAREN
    | ATKW      LPAREN atArgs RPAREN
    | CURSORKW  LPAREN argList? RPAREN
    | USE       LPAREN argList? RPAREN
    | LAYOUTKW  
    | LAYOUTKW  LPAREN argList? RPAREN
    | DISABLEKW
    | KEYKW     LPAREN argList? RPAREN
    | FULLKW
    | SCROLLKW
    | HIDEKW
    | FONTKW    LPAREN RPAREN
    | FONTKW    LPAREN fontArgList RPAREN
    | DROPIDKW  LPAREN argList? RPAREN
    | WIZARDKW
    | SPREADKW
    | HSCROLL
    | JOINKW
    | NOSHEETKW
    | COLORKW   LPAREN argList? RPAREN
    | UPKW
    | DOWNKW
    | LEFTKW 
    | LEFTKW LPAREN argList? RPAREN
    | RIGHTKW 
    | RIGHTKW LPAREN argList? RPAREN
    | ABOVEKW LPAREN argList? RPAREN
    | BELOWKW LPAREN argList? RPAREN
    | IMMKW
    ;

sheetTabDecl
    : ID? TABKW LPAREN argList? RPAREN controlAttrs lineEnd
    ;

controlType
    : BUTTON
    | LIST
    | ENTRY
    | STRINGKW
    | TEXTKW
    | BOX
    | PANEL
    | REGION
    | LINE
    | SLIDER
    | SPIN
    | ELLIPSE
    | IMAGE
    | OLE
    | PROMPTKW
    | RADIOKW
    | SHEETKW
    | TABKW
    | CHECKKW
    | PROGRESS
    ;

// Zero or more control attributes, with at most one alignAttr
controlAttrs
    : controlAttrsNoAlign
    | controlAttrsWithAlign
    ;

// Only non-align attributes
controlAttrsNoAlign
    : (COMMA nonAlignAttr)*
    ;

// Exactly one alignAttr, optionally surrounded by non-align attributes
controlAttrsWithAlign
    : (COMMA nonAlignAttr)*
      COMMA alignAttr
      (COMMA nonAlignAttr)*
    ;

// Attributes that define horizontal/decimal formatting; only one allowed per control
alignAttr
    : LEFTKW  (LPAREN expr RPAREN)?
    | RIGHTKW (LPAREN expr RPAREN)?
    | DECIMAL (LPAREN expr RPAREN)?
    ;

// Any single control attribute
controlAttr
    : alignAttr
    | nonAlignAttr
    ;

// All non-align attributes valid on controls (PROMPT, BUTTON, STRING, OLE, LIST, LINE, etc.)
nonAlignAttr
    // positional / layout / binding / data source
    : ATKW      LPAREN RPAREN
    | ATKW      LPAREN atArgs RPAREN
    | CURSORKW  LPAREN argList? RPAREN
    | USE       LPAREN argList? RPAREN
    | LAYOUTKW
    | LAYOUTKW  LPAREN argList? RPAREN
    | FONTKW    LPAREN RPAREN
    | FONTKW    LPAREN fontArgList RPAREN
    | COLORKW   LPAREN argList? RPAREN
    | DROPIDKW  LPAREN argList? RPAREN
    | ANGLEKW   LPAREN argList? RPAREN
    | COMPATIBILITYKW LPAREN argList? RPAREN
    | FROMKW    LPAREN argList? RPAREN
    | FORMATKW  LPAREN atArgs RPAREN
    | DRAGIDKW  LPAREN argList? RPAREN
    | PENKW     LPAREN argList? RPAREN
    | STYLEKW   LPAREN argList? RPAREN
    | LINEWIDTHKW LPAREN argList? RPAREN
    | LINEWIDTHKW

    // basic behavioral flags
    | DISABLEKW
    | HIDEKW
    | FULLKW
    | SCROLLKW
    | TRNKW
    | SKIPKW
    | DEFAULTKW
    | IMMKW
    | REQKW
    | FLATKW
    | BOXEDKW
    | CENTER
    | CENTERED
    | TILED
    | READONLYKW
    | MASK
    | INSKW
    | UPRKW
    | OVRKW
    | CAPKW

    // LIST/COMBO-specific simple flags
    | DROPKW (LPAREN expr RPAREN)?
    | COLUMNKW
    | VCRKW
    | NOBARKW
    | GRIDKW (LPAREN argList? RPAREN)?

    // scroll flags usable on controls
    | HSCROLL
    | VSCROLL
    | HVSCROLL

    // BUTTON/menu-style attributes with params
    | KEYKW     LPAREN argList? RPAREN
    | MSGKW     LPAREN argList? RPAREN
    | HLPKW     LPAREN argList? RPAREN
    | STDKW
    | STDKW     LPAREN argList? RPAREN
    | ICONKW    LPAREN argList? RPAREN
    | TIPKW     LPAREN argList? RPAREN
    | ALRTKW    LPAREN argList? RPAREN
    | REPEATKW  LPAREN atArgs RPAREN
    | DELAYKW   LPAREN argList? RPAREN

    // STRING/report-style aggregation / page counters
    | PAGENOKW                        // PAGENO
    | EXTENDKW LPAREN argList? RPAREN // EXTEND(...)
    | CNTKW    LPAREN argList? RPAREN // CNT(...)
    | SUMKW    LPAREN argList? RPAREN // SUM(...)
    | AVEKW    LPAREN argList? RPAREN // AVE(...)
    | MINKW    LPAREN argList? RPAREN // MIN(...)
    | MAXKW    LPAREN argList? RPAREN // MAX(...)
    | RESETKW  LPAREN argList? RPAREN // RESET(...)
    | TALLYKW  LPAREN argList? RPAREN // TALLY(...)
    | PAGEKW                          // PAGE

    // LIST MARK attribute
    | MARKKW   LPAREN argList? RPAREN

    // ellipse / box / line fill
    | BEVELKW  LPAREN bevelArgs RPAREN
    | FILLKW   (LPAREN argList? RPAREN)?

    // fallback custom attributes
    | ID
    | ID LPAREN argList? RPAREN
    ;

// REPORT

reportDecl
    : ID REPORTKW LPAREN argList? RPAREN
      COMMA ATKW      LPAREN atArgs RPAREN
      (COMMA reportAttr)* lineEnd
      reportSection*
      (END | DOT)
    ;

reportAttr
    : FONTKW   LPAREN RPAREN
    | FONTKW   LPAREN fontArgList RPAREN
    | PRE      LPAREN ID RPAREN
    | LANDSCAPEKW
    | PREVIEWKW
    | PAPERKW
    | COLORKW  LPAREN argList? RPAREN
    | THOUS
    | MMKW
    | POINTSKW
    | ID
    | ID LPAREN argList? RPAREN
    ;

reportSection
    : reportFormSection
    | reportHeaderSection
    | reportDetailSection
    | reportBreakSection
    | reportFooterSection
    ;

reportFormSection
    : FORMKW lineEnd
      reportControlDecl*
      (END | DOT)
    ;

reportHeaderSection
    : HEADERKW lineEnd
      reportControlDecl*
      (END | DOT)
    ;

reportDetailSection
    : ID DETAILKW lineEnd
      reportControlDecl*
      (END | DOT)
    ;

reportBreakSection
    : ID BREAK LPAREN argList? RPAREN lineEnd
      reportControlDecl*
      (END | DOT)
    ;

reportFooterSection
    : FOOTERKW lineEnd
      reportControlDecl*
      (END | DOT)
    ;

reportControlDecl
    : ID? PROMPTKW LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? BUTTON   LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? STRINGKW LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? CHECKKW  LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? IMAGE    LPAREN argList? RPAREN controlAttrs lineEnd
    | ID? OLE oleControlAttrs lineEnd oleMenuBarSection? (END | DOT)
    | ID? LINE lineControlAttrs lineEnd
    | ID? controlType (LPAREN argList? RPAREN)? controlAttrs lineEnd
    ;

// Procedure prototypes and impls

procedureProtoDecl
    : ID PROCEDUREKW (LPAREN procedureProtoParamList? RPAREN)?
      (COMMA returnType)?
      lineEnd
    ;

procedureDecl
    : ID PROCEDUREKW (LPAREN procedureProtoParamList? RPAREN)?
      (COMMA returnType)? lineEnd
      declarationSection*
      codeSection
    ;

returnType
    : STAR? typeSpec   // allow plain type or *type as return type
    ;

moduleDecl2
    : MODULE LPAREN expr RPAREN lineEnd
      prototypeDecl*
      (END | DOT)
    ;

// Label / picture / type

labelDecl
    : ID EQUATE LPAREN expr? RPAREN lineEnd
    | PICTURE (COMMA labelAttr)* lineEnd
    | builtinType lineEnd
    // BFLOAT4 label with optional initial value and attributes
    | BFLOAT4 LPAREN expr? RPAREN (COMMA labelAttr)* lineEnd
    // BFLOAT8 label with optional initial value and attributes
    | BFLOAT8 LPAREN expr? RPAREN (COMMA labelAttr)* lineEnd
    ;

labelAttr
    : STATIC
    | THREAD
    | AUTO
    | PRIVATE
    | PROTECTED
    | DIM LPAREN expr (COMMA expr)* RPAREN
    | OVER LPAREN fieldRef RPAREN
    | NAMEKW LPAREN expr? RPAREN
    | EXTERNAL
    | DLL LPAREN argList? RPAREN
    ;

// ITEMIZE

itemizeDecl
    : ID? ITEMIZEKW LPAREN expr? RPAREN
      (COMMA PRE LPAREN expr? RPAREN)?
      lineEnd
      itemizeEquate+
      (END | DOT)
    ;

itemizeEquate
    : ID EQUATE LPAREN expr? RPAREN lineEnd
    ;

// RECORD

recordDecl
    : ID RECORD (COMMA recordAttr)* lineEnd
      recordFieldDecl+
      (END | DOT)
    ;

recordAttr
    : PRE LPAREN ID RPAREN
    | ID
    | ID LPAREN argList? RPAREN
    ;

recordFieldDecl
    : ID dataLikeOrType? (COMMA dataAttr)* lineEnd
    ;

// GROUP

groupDecl
    : ID? GROUP LPAREN fieldRef? RPAREN (COMMA groupAttr)* lineEnd
      declarationSection*
      (END | DOT)
    ;

groupAttr
    : PRE LPAREN ID RPAREN
    | DIM LPAREN expr (COMMA expr)* RPAREN
    | OVER LPAREN fieldRef RPAREN
    | ID
    | ID LPAREN argList? RPAREN
    ;

// FILE

fileDecl
    : ID FILE (COMMA fileAttr)* lineEnd
      fileEntry*
      (END | DOT)
    ;

fileAttr
    : PRE LPAREN ID RPAREN
    | ID
    | ID LPAREN argList? RPAREN
    ;

fileEntry
    : recordDecl
    | fileKeyDecl
    | fileIndexDecl
    | fileMemoDecl
    | fileBlobDecl
    ;

// VIEW declarations

viewDecl
    : ID VIEW LPAREN fieldRef RPAREN (COMMA viewAttr)* lineEnd
      viewSection*
      (END | DOT)
    ;

viewAttr
    : FILTERKW LPAREN expr RPAREN
    | ORDERKW  LPAREN expr RPAREN
    ;

viewSection
    : projectSection
    | joinSection
    ;

projectSection
    : PROJECTKW LPAREN projectList? RPAREN lineEnd
    ;

projectList
    : fieldRef (COMMA fieldRef)*
    ;

joinSection
    : JOINKW LPAREN fieldRef RPAREN lineEnd
      viewSection*
      (END | DOT)
    ;

// FILE KEY

fileKeyDecl
    : ID (KEYKW LPAREN keyFieldList RPAREN keyAttrList)? lineEnd
    ;

keyFieldList
    : keyField (COMMA keyField)*
    ;

keyField
    : (PLUS | MINUS)? fieldRef
    ;

keyAttrList
    : (COMMA keyAttr)+
    ;

keyAttr
    : ID
    | ID LPAREN argList? RPAREN
    ;

fileIndexDecl
    : ID (INDEXKW LPAREN argList? RPAREN)? lineEnd
    ;

fileMemoDecl
    : ID (MEMO LPAREN argList? RPAREN)? lineEnd
    ;

fileBlobDecl
    : ID (BLOB)? lineEnd
    ;

// INTERFACE

interfaceDecl
    : ID INTERFACE LPAREN fieldRef? RPAREN
      (COMMA TYPEKW)?
      (COMMA COMKW)?
      lineEnd
      interfaceMethod*
      (END | DOT)
    ;

interfaceMethod
    : prototypeDecl
    ;

// CLASS

classDecl
    : ID CLASSKW LPAREN fieldRef? RPAREN classAttrList? lineEnd
      classMember*
      (END | DOT)
    ;

classAttrList
    : COMMA classAttr (COMMA classAttr)*
    ;

classAttr
    : EXTERNAL
    | IMPLEMENTS
    | DLL LPAREN expr? RPAREN
    | STATIC
    | THREAD
    | BINDABLE
    | MODULE LPAREN expr? RPAREN
    | LINKKW LPAREN expr? RPAREN
    | TYPEKW
    | DIM LPAREN expr RPAREN
    | PARTIALKW
    ;

classMember
    : dataDecl
    | prototypeDecl
    ;

// KEYWORD construct

keywordDecl
    : ID? KEYWORDKW LPAREN keywordParamList RPAREN keywordAttr* lineEnd
    ;

keywordParamList
    : PIPE? expr (PIPE expr)* PIPE?
    ;

keywordAttr
    : ID LPAREN argList? RPAREN
    ;

// CODE and statements

codeSection
    : CODE lineEnd statement*
    ;

statement
    : QUESTION? coreStatement
    | lineEnd
    ;

coreStatement
    : assignStmt
    | procCallStmt
    | doStmt
    | ifStmt
    | caseStmt
    | executeStmt
    | loopStmt
    | acceptStmt
    | breakStmt
    | cycleStmt
    | exitStmt
    | routineStmt
    | routineDataBlock
    | codeMarkerStmt
    | includeStmt
    | returnStmt
    | openCloseStmt
    | lineFuncStmt
    | ellipseFuncStmt
    | imageFuncStmt
    | gotoStmt
    | bindStmt
    | unbindStmt
    ;

// BIND

bindStmt
    : BINDKW LPAREN bindSpec RPAREN lineEnd
    ;

unbindStmt
    : UNBINDKW LPAREN expr? RPAREN lineEnd
    ;

bindSpec
    // name, variable | name, procedure
    : ID COMMA fieldRef
    // group
    | fieldRef
    ;

// Assignments / calls

assignStmt
    : fieldRef (EQUAL | AMP_EQUAL | DEEP_ASSIGN | STAR_EQUAL | PLUS_EQUAL | DIV_EQUAL) expr lineEnd
    ;

procCallStmt
    : fieldRef LPAREN argList? RPAREN lineEnd
    ;

doStmt
    : DO fieldRef lineEnd
    ;

includeStmt
    : INCLUDEKW LPAREN expr (COMMA expr)? RPAREN (COMMA ONCEKW)? lineEnd
    ;

// EXECUTE

executeStmt
    : EXECUTE expr lineEnd
      executeBranch+
      executeElse?
      (END | DOT)
    ;

executeBranch
    : BEGIN lineEnd statement* (END | DOT)
    | statement
    ;

executeElse
    : ELSE lineEnd statement*
    ;

// IMAGE drawing function
imageFuncStmt
    : IMAGE LPAREN imageArgs RPAREN lineEnd
    ;

imageArgs
    : expr COMMA expr (COMMA expr)? (COMMA expr)? COMMA expr (COMMA argList)?
    ;

ellipseFuncStmt
    : ELLIPSE LPAREN argList? RPAREN lineEnd
    ;

// IF

ifStmt
    : IF expr (THEN)? lineEnd
      statement*
      elsifClause*
      elseClause?
      (END | DOT)
    ;

elsifClause
    : ELSIF expr (THEN)? lineEnd
      statement*
    ;

elseClause
    : ELSE lineEnd
      statement*
    ;

// CASE

caseStmt
    : CASE expr lineEnd
      caseBranch*
      (ELSE lineEnd statement*)?
      (END | DOT)
    ;

caseBranch
    : OF caseLabel (OROF caseLabel)* lineEnd
      statement*
    ;

caseLabel
    : expr (TO expr)?
    ;

// LOOP

loopStmt
    : (ID)? LOOP loopHead? lineEnd
      statement*
      loopTail?
      (END | DOT)
    ;

loopHead
    : expr TIMES
    | ID EQUAL expr TO expr (BY expr)?
    | UNTIL expr
    | WHILE expr
    ;

loopTail
    : UNTIL expr
    | WHILE expr
    ;

// ACCEPT / BREAK / etc.

acceptStmt
    : ACCEPT lineEnd statement* (END | DOT)
    ;

breakStmt
    : BREAK (ID)? lineEnd
    ;

cycleStmt
    : CYCLE (ID)? lineEnd
    ;

exitStmt
    : EXIT lineEnd
    ;

routineStmt
    : ID ROUTINE lineEnd
    ;

routineDataBlock
    : DATAKW lineEnd
      declarationSection*
    ;

codeMarkerStmt
    : CODE lineEnd
    ;

returnStmt
    : RETURN expr? lineEnd
    ;

openCloseStmt
    : (OPEN | CLOSE) LPAREN fieldRef RPAREN lineEnd
    ;

gotoStmt
    : GOTO ID lineEnd
    ;

lineFuncStmt
    : LINE LPAREN lineCoordArgs RPAREN lineEnd
    ;

lineCoordArgs
    : expr COMMA expr COMMA expr COMMA expr (COMMA argList)?
    ;

expr
    : orExpr
    ;

orExpr
    : andExpr (OR andExpr)*
    ;

andExpr
    : equalityExpr (AND equalityExpr)*
    ;

equalityExpr
    : relationalExpr ((EQUAL | NEQ | AMP_EQUAL) relationalExpr)*
    ;

relationalExpr
    : additiveExpr ((LT | LTE | GT | GTE) additiveExpr)*
    ;

additiveExpr
    : multiplicativeExpr ((PLUS | MINUS | AMP) multiplicativeExpr)*
    ;

multiplicativeExpr
    : powExpr ((STAR | DIV | PERCENT) powExpr)*
    ;

powExpr
    : unaryExpr (CARET powExpr)?
    ;

unaryExpr
    : (NOT | TILDE | MINUS) unaryExpr
    | primary
    ;

primary
    : primaryBase
      ( LBRACE propertyParamList RBRACE
      | LBRACE expr RBRACE
      | LBRACKET indexOrSlice RBRACKET
      )*
    ;

primaryBase
    : literal
    | fieldRef
    | ADDRESS LPAREN argList? RPAREN
    | LIKE LPAREN argList? RPAREN
    | POPUPKW LPAREN popupArgList RPAREN
    | LINKNAMEKW LPAREN argList? RPAREN
    | LINEWIDTHKW LPAREN argList? RPAREN
    | PROJECTKW LPAREN argList? RPAREN
    | PEEKKW LPAREN expr COMMA expr RPAREN
    | POKEKW LPAREN expr COMMA expr RPAREN
    | FORMATKW LPAREN expr COMMA expr RPAREN
    | DEFORMATKW LPAREN expr (COMMA expr)? RPAREN
    | LPAREN expr RPAREN
    ;

popupArgList
    : expr (COMMA expr)? (COMMA expr)? (COMMA expr)?
    ;

indexOrSlice
    : expr
    | expr SLICE_COLON expr?
    | SLICE_COLON expr?
    ;

propertyParamList
    : expr (COMMA expr)*
    ;

literal
    : INTLIT
    | HEXLIT
    | OCTLIT
    | BINLIT
    | REALLIT
    | STRING
    | TRUE
    | FALSE
    | PICTURE
    | NULLKW
    ;

fieldRef
    : ID (DOT ID)*
    ;

// Lexer rules

RECORD      : 'RECORD';
PROGRAM     : 'PROGRAM';
MAP         : 'MAP';
MODULE      : 'MODULE';
END         : 'END';
CODE        : 'CODE';
DATAKW      : 'DATA';
MEMBER      : 'MEMBER';

BYTE        : 'BYTE';
SHORT       : 'SHORT';
USHORT      : 'USHORT';
LONG        : 'LONG';
ULONG       : 'ULONG';
DECIMAL     : 'DECIMAL';
PDECIMAL    : 'PDECIMAL';
REAL        : 'REAL';
SREAL       : 'SREAL';
BFLOAT8     : 'BFLOAT8';
BFLOAT4     : 'BFLOAT4';
STRINGKW    : 'STRING';
TEXTKW      : 'TEXT';
CSTRING     : 'CSTRING';
BSTRING     : 'BSTRING';
PSTRING     : 'PSTRING';
USTRING     : 'USTRING';
BLOB        : 'BLOB';
MEMO        : 'MEMO';
DATE        : 'DATE';
TIME        : 'TIME';
BOOL        : 'BOOL';
QUEUE       : 'QUEUE';
VIEW        : 'VIEW';
WINDOW      : 'WINDOW';
APPLICATION : 'APPLICATION';
FILE        : 'FILE';
GROUP       : 'GROUP';
VARIANT     : 'VARIANT';
ANY         : 'ANY';

PRE         : 'PRE';
USE         : 'USE';
LIKE        : 'LIKE';
DIM         : 'DIM';
OVER        : 'OVER';
STATIC      : 'STATIC';
PRIVATE     : 'PRIVATE';
THREAD      : 'THREAD';
AUTO        : 'AUTO';
BINARYKW    : 'BINARY';

BUTTON      : 'BUTTON';
LIST        : 'LIST';
ENTRY       : 'ENTRY';
BOX         : 'BOX';
PANEL       : 'PANEL';
REGION      : 'REGION';
LINE        : 'LINE';
SLIDER      : 'SLIDER';
SPIN        : 'SPIN';
ELLIPSE     : 'ELLIPSE';
IMAGE       : 'IMAGE';
OLE         : 'OLE';
PROMPTKW    : 'PROMPT';
RADIOKW     : 'RADIO';
SHEETKW     : 'SHEET';
TABKW       : 'TAB';
CHECKKW     : 'CHECK';
COMBOKW     : 'COMBO';
PROGRESS    : 'PROGRESS';

OPTIONKW    : 'OPTION';
BOXEDKW     : 'BOXED';
BEVELKW     : 'BEVEL';

PROC        : 'PROC';
ACCEPT      : 'ACCEPT';
CASE        : 'CASE';
OF          : 'OF';
OROF        : 'OROF';
ELSE        : 'ELSE';
ELSIF       : 'ELSIF';
IF          : 'IF';
THEN        : 'THEN';
LOOP        : 'LOOP';
BREAK       : 'BREAK';
CYCLE       : 'CYCLE';
EXIT        : 'EXIT';
GOTO        : 'GOTO';
ROUTINE     : 'ROUTINE';
RETURN      : 'RETURN';
OPEN        : 'OPEN';
CLOSE       : 'CLOSE';
DO          : 'DO';
EXECUTE     : 'EXECUTE';
BEGIN       : 'BEGIN';
TRUE        : 'TRUE';
FALSE       : 'FALSE';
AND         : 'AND';
OR          : 'OR';
NOT         : 'NOT';
TO          : 'TO';
ADDRESS     : 'ADDRESS';
EQUATE      : 'EQUATE';
TIMES       : 'TIMES';
WHILE       : 'WHILE';
UNTIL       : 'UNTIL';
BY          : 'BY';
INTERFACE   : 'INTERFACE';
TYPEKW      : 'TYPE';
COMKW       : 'COM';
CLASSKW     : 'CLASS';
EXTERNAL    : 'EXTERNAL';
IMPLEMENTS  : 'IMPLEMENTS';
DLL         : 'DLL';
BINDABLE    : 'BINDABLE';
LINKKW      : 'LINK';
NAMEKW      : 'NAME';
BINDKW      : 'BIND';
UNBINDKW    : 'UNBIND';
PARTIALKW   : 'PARTIAL';
PROCEDUREKW : 'PROCEDURE';
ITEMIZEKW   : 'ITEMIZE';
INCLUDEKW   : 'INCLUDE';
ONCEKW      : 'ONCE';
KEYKW       : 'KEY';
INDEXKW     : 'INDEX';
NULLKW      : 'NULL';
KEYWORDKW   : 'KEYWORD';
PROTECTED   : 'PROTECTED';

MENUBAR     : 'MENUBAR';
TOOLBAR     : 'TOOLBAR';
MENU        : 'MENU';
ITEMKW      : 'ITEM';
STDKW       : 'STD';
RIGHTKW     : 'RIGHT';
DISABLEKW   : 'DISABLE';
LEFTKW      : 'LEFT';
HIDEKW      : 'HIDE';
FIRSTKW     : 'FIRST';
LASTKW      : 'LAST';
SEPARATORKW : 'SEPARATOR';
NOMERGEKW   : 'NOMERGE';
WALLPAPERKW : 'WALLPAPER';
POPUPKW     : 'POPUP';
LINKNAMEKW  : 'LINKNAME';
PEEKKW      : 'PEEK';
POKEKW      : 'POKE';
FULLKW      : 'FULL';
SCROLLKW    : 'SCROLL';
TRNKW       : 'TRN';
SKIPKW      : 'SKIP';
DEFAULTKW   : 'DEFAULT';
REQKW       : 'REQ';
TIPKW       : 'TIP';
FLATKW      : 'FLAT';
REPEATKW    : 'REPEAT';
DELAYKW     : 'DELAY';

REPORTKW    : 'REPORT';
ATKW        : 'AT';
FONTKW      : 'FONT';
COLORKW     : 'COLOR';

CENTER      : 'CENTER';
CENTERED    : 'CENTERED';
SYSTEMKW    : 'SYSTEM';
MAXKW       : 'MAX';
ICONKW      : 'ICON';
STATUSKW    : 'STATUS';
HLPKW       : 'HLP';
CURSORKW    : 'CURSOR';
MDI         : 'MDI';
MODAL       : 'MODAL';
MASK        : 'MASK';
GRAY        : 'GRAY';
TIMERKW     : 'TIMER';
ALRTKW      : 'ALRT';
ICONIZE     : 'ICONIZE';
MAXIMIZE    : 'MAXIMIZE';
MSGKW       : 'MSG';
PALETTEKW   : 'PALETTE';
DROPIDKW    : 'DROPID';
IMMKW       : 'IMM';
TOOLBOX     : 'TOOLBOX';
DOCKKW      : 'DOCK';
DOCKEDKW    : 'DOCKED';
LAYOUTKW    : 'LAYOUT';
TILED       : 'TILED';
HSCROLL     : 'HSCROLL';
VSCROLL     : 'VSCROLL';
NOFRAME     : 'NOFRAME';
HVSCROLL    : 'HVSCROLL';
RESIZEKW    : 'RESIZE';
DOUBLE      : 'DOUBLE';

FORMKW      : 'FORM';
HEADERKW    : 'HEADER';
DETAILKW    : 'DETAIL';
FOOTERKW    : 'FOOTER';
LANDSCAPEKW : 'LANDSCAPE';
PREVIEWKW   : 'PREVIEW';
PAPERKW     : 'PAPER';
THOUS       : 'THOUS';
MMKW        : 'MM';
POINTSKW    : 'POINTS';

PAGENOKW    : 'PAGENO';
EXTENDKW    : 'EXTEND';
CNTKW       : 'CNT';
SUMKW       : 'SUM';
AVEKW       : 'AVE';
MINKW       : 'MIN';
TALLYKW     : 'TALLY';
RESETKW     : 'RESET';
PAGEKW      : 'PAGE';
ANGLEKW     : 'ANGLE';
COMPATIBILITYKW : 'COMPATIBILITY';
FROMKW      : 'FROM';
FORMATKW    : 'FORMAT';
DEFORMATKW  : 'DEFORMAT';
DROPKW      : 'DROP';
COLUMNKW    : 'COLUMN';
VCRKW       : 'VCR';
NOBARKW     : 'NOBAR';
GRIDKW      : 'GRID';
MARKKW      : 'MARK';
DRAGIDKW    : 'DRAGID';
PENKW       : 'PEN';
STYLEKW     : 'STYLE';
LINEWIDTHKW : 'LINEWIDTH';
READONLYKW  : 'READONLY';
INSKW       : 'INS';
UPRKW       : 'UPR';
OVRKW       : 'OVR';
CAPKW       : 'CAP';
FILLKW      : 'FILL';

WIZARDKW    : 'WIZARD';
SPREADKW    : 'SPREAD';
JOINKW      : 'JOIN';
NOSHEETKW   : 'NOSHEET';
UPKW        : 'UP';
DOWNKW      : 'DOWN';
ABOVEKW     : 'ABOVE';
BELOWKW     : 'BELOW';

FILTERKW    : 'FILTER';
ORDERKW     : 'ORDER';
PROJECTKW   : 'PROJECT';

LTE         : '<=';
GTE         : '>=';
NEQ         : '<>';
AMP_EQUAL   : '&=';
DEEP_ASSIGN : ':=:';
STAR_EQUAL  : '*=';
PLUS_EQUAL  : '+=';
DIV_EQUAL   : '/=';

SLICE_COLON : ':';

LT          : '<';
GT          : '>';
EQUAL       : '=';

CARET       : '^';
PLUS        : '+';
MINUS       : '-';
STAR        : '*';
DIV         : '/';
PERCENT     : '%';
TILDE       : '~';
AMP         : '&';
DOT         : '.';

LPAREN      : '(' ;
RPAREN      : ')' ;
LBRACE      : '{' ;
RBRACE      : '}' ;
LBRACKET    : '[' ;
RBRACKET    : ']' ;
COMMA       : ',' ;

QUESTION    : '?';
PIPE        : '|';

HEXLIT      : '0' [0-9a-f]* 'h' ;
OCTLIT      : [0-7]+ 'o' ;
BINLIT      : [01]+ 'b' ;
INTLIT      : [0-9]+ ;
REALLIT     : [0-9]+ '.' [0-9]+ ;

// match '...' with backslash escapes inside
STRING
    : '\'' ( ~['\\] | '\\' . )* '\''
    ;

PICTURE
    : '@' ~[ \t\r\n,;(){}[\]]+
    ;

EOL
    : [\r\n]+
    ;

NEWLINE
    : ';'
    ;

ID
    : QUESTION? ID_START ID_PART* ('#' | '$' | '"')?
    ;

fragment ID_START : [a-z_];
fragment ID_PART  : [a-z0-9_:$];

LINE_CONTINUATION
    : '|' [ \t]* [\r\n]+ -> skip
    ;

LINE_COMMENT
    : '!' ~[\r\n]* -> skip
    ;

WS
    : [ \t\f]+ -> skip
    ;

Here is the test file

   PROGRAM
   MAP
   END
   
   Window               WINDOW('ClassViewer'),AT(,,318,228),FONT('Microsoft Sans Serif',10,,FONT:regular,CHARSET:DEFAULT), |
  RESIZE,TILED,ALRT(BSKey),ALRT(CtrlF5),ALRT(CtrlShiftQ),ALRT(CtrlShiftR),ALRT(EscKey),ALRT(F5Key), |
  ALRT(MinusKey),ALRT(PlusKey),ALRT(SpaceKey),CENTER,ICON('abcview.ico'),GRAY,IMM,MAX,PALETTE(256), |
  SYSTEM,TIMER(10),WALLPAPER('WALLPAPER.GIF')
                       MENUBAR,USE(?MenuBar)
                         MENU('&File'),USE(?File)
                           ITEM('Clarion &12.0'),USE(FileClarion120),CHECK
                           ITEM('Clarion &11.1'),USE(FileClarion111),CHECK
                           ITEM('Clarion &11'),USE(FileClarion110),CHECK
                           ITEM('Clarion &10'),USE(FileClarion100),CHECK
                           ITEM('Clarion &9'),USE(FileClarion90),CHECK
                           ITEM('Clarion &8'),USE(FileClarion80),CHECK
                           ITEM('Clarion &7'),USE(FileClarion70),CHECK
                           ITEM('Clarion &6.0 EE'),USE(FileClarion60EE),CHECK
                           ITEM('Clarion &6.0'),USE(FileClarion60),CHECK
                           ITEM('Clarion &5.5 EE'),USE(FileClarion55EE),CHECK
                           ITEM('Clarion &5.5'),USE(FileClarion55),CHECK
                           ITEM('&Clarion 5.0 EE'),USE(FileClarion50EE),CHECK
                           ITEM('&Clarion 5.0'),USE(FileClarion50),CHECK
                           ITEM('Clarion &4.0'),USE(FileClarion40),CHECK
                           ITEM('Clarion &2.0'),USE(FileClarion20),CHECK
                           ITEM,USE(?SEPARATOR1),SEPARATOR
                           MENU('&Recent'),USE(?FileRecent)
                           END
                           ITEM,USE(?SEPARATOR2),SEPARATOR
                           ITEM('E&xit'),USE(?FileExit)
                         END
                         MENU('&Tree'),USE(?Tree)
                           ITEM('E&xpand All<09H>    Ctrl+Grey Plus'),USE(?TreeExpand),LEFT(16),KEY(CtrlPlus),ICON('expand.ico')
                           ITEM('C&ontract All<09H>    Ctrl+Grey Minus'),USE(?TreeContract),LEFT(16),KEY(CtrlMinus),ICON('contract.ico')
                           ITEM,USE(?SEPARATOR3),SEPARATOR
                           ITEM('&Expand Branch<09H>    Grey Plus'),USE(?TreeExpandBranch),LEFT(16),KEY(PlusKey)
                           ITEM('&Contract Branch<09H>    Grey Minus'),USE(?TreeContractBranch),LEFT(16),KEY(MinusKey)
                           ITEM,USE(?SEPARATOR4),SEPARATOR
                         END
                         MENU('&View'),USE(?View)
                           ITEM('C&lasses    <09H>Ctrl+L'),USE(bViewClasses),LEFT(16),KEY(CtrlL),CHECK,ICON('class.ico')
                           ITEM('&Interfaces<09H>Ctrl+I'),USE(bViewInterfaces),LEFT(16),KEY(CtrlI),CHECK,ICON('intrface.ico')
                           ITEM('Call &Tree<09H>Ctrl+T'),USE(bViewCallTree),LEFT(16),KEY(CtrlT),CHECK,ICON('tree.ico')
                           ITEM('Str&uctures<09H>Ctrl+U'),USE(bViewStructures),LEFT(16),KEY(CtrlU),CHECK,ICON('structyp.ico')
                           ITEM('&Equates    <09H>Ctrl+E'),USE(bViewEquates),LEFT(16),KEY(CtrlE),CHECK,ICON('efolder.ico')
                           ITEM,USE(?SEPARATOR5),SEPARATOR
                           ITEM('&Definition<09H>Ctrl+Enter'),USE(?ViewSource),LEFT(16),KEY(CtrlEnter),ICON('data.ico')
                           ITEM('&Help        <09H>Ctrl+H'),USE(?ViewHelp),LEFT(16),KEY(CtrlH),ICON('help.ico')
                           ITEM('&Notes    <09H>Ctrl+N'),USE(?ViewNotes),LEFT(16),KEY(CtrlN),ICON('note.ico')
                         END
                         MENU('T&ools'),USE(?Tools)
                           ITEM('&Options...<09H> {14}Ctrl+O'),AT(,,80),USE(?ToolsOptions),LEFT(16),KEY(CtrlO),ICON('options.ico')
                           ITEM('&Refresh Tree<09H> {14}Ctrl+R'),AT(,,80),USE(?ToolsRefreshTree),LEFT(16),KEY(CtrlR), |
  ICON('refresh.ico')
                           ITEM('Add Class &Wizard<09H>Ctrl+W'),AT(,,80),USE(?ToolsAddClassWizard),LEFT(16),KEY(CtrlW), |
  ICON('classwiz.ico')
                           ITEM('&Browse Database<09H>Ctrl+B'),AT(,,80),USE(?ToolsBrowseDatabase),LEFT(16),KEY(CtrlB), |
  ICON('BrowseDatabase.ico')
                           ITEM('&Statistics<09H> {14}Ctrl+S'),USE(?ToolsStatistics),LEFT(16),KEY(CtrlS),ICON('stats.ico')
                           ITEM('&Calculator<09H> {14}Ctrl+Shift+C'),USE(?ToolsCalculator),LEFT(16),KEY(CtrlShiftC),ICON('calc.ico')
                           ITEM,USE(?SEPARATOR6),SEPARATOR
                           MENU('Fa&vorites'),USE(?ToolsFavorites),LEFT(16)
                             ITEM('&Edit Favorites...'),USE(?ToolsFavoritesAddtoFavorites)
                           END
                           ITEM('&Find Notes<09H> {14}Ctrl+F'),USE(?ToolsFindNotes),LEFT(16),KEY(CtrlF)
                           ITEM('Clear Histor&y<09H> {14}Ctrl+Y'),AT(,,80),USE(?ToolsClearHistory),LEFT(16),KEY(CtrlY), |
  DISABLE
                           ITEM('Add to Clarion &Menu'),USE(?HelpAddtoClarionMenu),LEFT(16),ICON('cw.ico')
                           ITEM,USE(?SEPARATOR7),SEPARATOR
                           MENU('&XML Export'),USE(?ToolsXMLExport),LEFT(16)
                             ITEM('&Database to XML'),USE(?FileExportToXML)
                             ITEM('&Tree to XML'),USE(?TreeExportToXML)
                           END
                         END
                         MENU('&Help'),USE(?HelpMenu),MSG('Windows Help')
                           ITEM('&Contents'),USE(?HelpContents),LEFT(16),ICON('HelpContents.ico'),MSG('View the co' & |
  'ntents of the help file')
                           ITEM('&Search for Help On...'),USE(?HelpSearch),LEFT(16),MSG('Search for help on a subject'), |
  STD(STD:HelpSearch)
                           ITEM('&How to Use Help'),USE(?HelpOnHelp),LEFT(16),MSG('How to use Windows Help'),STD(STD:HelpOnHelp)
                           ITEM,USE(?SEPARATOR8),SEPARATOR
                           ITEM('&About Class Viewer'),USE(?HelpAboutClassViewer),LEFT(16),ICON('Help.ICO')
                           ITEM('Just the FA&Qs'),USE(?HelpJusttheFAQs),LEFT(16),ICON('RedPin.ico')
                         END
                       END
                       PANEL,AT(0,0,,0),USE(?Panel4),FULL,BEVEL(0,0,2048)
                       IMAGE('toolbar.bmp'),AT(0,0,,14),USE(?Image13),FULL
                       PANEL,AT(0,14,,14),USE(?Panel4:2),FULL,BEVEL(0,0,2048),FILL(00E2A981h)
                       PANEL,AT(0,28,,2),USE(?Panel4:3),FULL,BEVEL(0,0,2048)
                       LIST,AT(8,32,100,174),USE(?ObjectDropList),FONT(,,COLOR:INACTIVECAPTION,,CHARSET:ANSI),LEFT(2), |
  VSCROLL,ALRT(MouseRight),ALRT(EnterKey),COLOR(COLOR:White,COLOR:White,COLOR:INACTIVECAPTION), |
  FORMAT('252L(2)|T@s63@'),FROM(ClassQ)
                       BUTTON,AT(4,1,12,12),USE(?ExpandButton),ICON('expand.ico'),FLAT,SKIP,TIP('Expand Tree')
                       BUTTON,AT(18,1,12,12),USE(?ContractButton),ICON('contract.ico'),FLAT,SKIP,TIP('Contract Tree')
                       PANEL,AT(32,1,2,12),USE(?Panel5),BEVEL(0,0,24576)
                       REGION,AT(108,32,2,192),USE(?SplitterBar),IMM
                       BUTTON,AT(35,1,12,12),USE(?ClassRegion),ICON('class.ico'),FLAT,SKIP,TIP('View Classes')
                       BUTTON,AT(49,1,12,12),USE(?InterfaceRegion),ICON('intrface.ico'),FLAT,SKIP,TIP('View Interfaces')
                       BUTTON,AT(63,1,12,12),USE(?TreeRegion),ICON('tree.ico'),FLAT,SKIP,TIP('View Method Call Tree')
                       BUTTON,AT(77,1,12,12),USE(?StructureRegion),ICON('structyp.ico'),FLAT,SKIP,TIP('View Structures')
                       BUTTON,AT(91,1,12,12),USE(?EquateRegion),ICON('efolder.ico'),FLAT,SKIP,TIP('View Equates')
                       PANEL,AT(105,1,2,12),USE(?Panel2),BEVEL(0,0,24576)
                       BUTTON,AT(108,1,12,12),USE(?ViewSourceButton),ICON('data.ico'),FLAT,SKIP,TIP('View Source File')
                       BUTTON,AT(122,1,12,12),USE(?HelpButton),ICON('help.ico'),FLAT,SKIP,TIP('View Clarion Help')
                       BUTTON,AT(136,1,12,12),USE(?ViewNoteButton),ICON('note.ico'),FLAT,SKIP,TIP('View Progra' & |
  'mmer Notes')
                       PANEL,AT(150,1,2,12),USE(?Panel3),BEVEL(0,0,24576)
                       BUTTON,AT(153,1,12,12),USE(?OptionsButton),ICON('options.ico'),FLAT,SKIP,TIP('Edit Appli' & |
  'cation Options')
                       BUTTON,AT(167,1,12,12),USE(?RefreshButton),ICON('refresh.ico'),FLAT,SKIP,TIP('Refresh Tree')
                       BUTTON,AT(181,1,12,12),USE(?AddClassWizardButton),ICON('classwiz.ico'),FLAT,SKIP,TIP('Add Class Wizard')
                       BUTTON,AT(195,1,12,12),USE(?CallTreeButton),ICON('BrowseDatabase.ico'),FLAT,SKIP,TIP('Browse Database')
                       PANEL,AT(209,1,2,12),USE(?Panel6),BEVEL(0,0,24576)
                       PROMPT('&Category:'),AT(10,17,29,8),USE(?glo:szCategory:Prompt),TRN
                       LIST,AT(40,16,50,10),USE(glo:szCategoryChoice),LEFT(2),VSCROLL,DROP(20),FORMAT('80L(2)@s20@'), |
  FROM(CategoryQueue),TIP('Select Category Filter')
                       PROMPT('&Detail:'),AT(116,17,24,8),USE(?glo:bDetailLevel:Prompt),TRN
                       SPIN(@n3),AT(142,16,14,10),USE(glo:bDetailLevel),CENTER,COLOR(COLOR:White),RANGE(0,9),STEP(1), |
  TIP('Select Detail Level')
                       PANEL,AT(108,14,2,14),USE(?SplitterBar:2),BEVEL(0,0,20640)
                       BUTTON,AT(264,2,10,10),USE(?HyperlinkButton),ICON('REDO.ICO'),DISABLE,FLAT,TIP('Hyperlink')
                       BUTTON,AT(276,2,10,10),USE(?PrevHyperlink),ICON('LEFTXP16.ICO'),DISABLE,FLAT,TIP('Move to Pr' & |
  'evious Hyperlink')
                       BUTTON,AT(288,2,10,10),USE(?NextHyperlink),ICON('RIGHTXP16.ICO'),DISABLE,FLAT,TIP('Move to Ne' & |
  'xt Hyperlink')
                       LIST,AT(300,2,10,10),USE(?HistoryList),VSCROLL,COLOR(COLOR:White),DISABLE,DROP(10),FLAT,FORMAT('120L(2)~Hy' & |
  'perlink History~@s30@'),FROM(HistoryQueue),TIP('HyperLink History')
                       LIST,AT(110,32,200,98),USE(?TreeList),FONT(,,COLOR:INACTIVECAPTION,,CHARSET:ANSI),VSCROLL, |
  ALRT(MouseRight),ALRT(MouseLeft2),COLOR(COLOR:White,COLOR:White,COLOR:INACTIVECAPTION),FORMAT('8L|IP@p p@' & |
  '250LIYPTS(1024)@s255@'),FROM(TreeQ),TIP('Double Click to Open.')
                       LIST,AT(110,133,200,74),USE(?AsciiBox),FONT('Courier New',9,,FONT:regular,CHARSET:ANSI),VSCROLL, |
  ALRT(MouseLeft2),COLOR(COLOR:White),IMM
                       TEXT,AT(110,133,200,74),USE(?sciControl:Region),BOXED
                       STRING(@s255),AT(110,158,154,6),USE(loc:szAsciiFilename),FONT('Tahoma',7,COLOR:Black,FONT:regular, |
  CHARSET:ANSI),LEFT,TRN
                       REGION,AT(110,130,200,2),USE(?VerticalSplitter),IMM
                       IMAGE('pick.ico'),AT(8,207,10,8),USE(?LocatorImage),CENTERED
                       STRING(''),AT(18,207,100),USE(?locator),FONT('Tahoma',8,,FONT:regular,CHARSET:ANSI),LEFT(2), |
  TRN
                       BOX,AT(8,216,10,8),USE(?VirtualBox),COLOR(00B99D7Fh),FILL(COLOR:Fuchsia),HIDE,LINEWIDTH(1), |
  ROUND
                       STRING('Virtual'),AT(20,215),USE(?VirtualString),TRN
                       BOX,AT(56,216,10,8),USE(?ProtectedBox),COLOR(00B99D7Fh),FILL(COLOR:Maroon),HIDE,LINEWIDTH(1), |
  ROUND
                       STRING('Protected'),AT(68,215),USE(?ProtectedString),TRN
                       BOX,AT(108,216,10,8),USE(?PrivateBox),COLOR(00B99D7Fh),FILL(COLOR:Red),HIDE,LINEWIDTH(1),ROUND
                       STRING('Private'),AT(120,215),USE(?PrivateString),TRN
                       BOX,AT(152,216,10,8),USE(?ModuleBox),COLOR(00B99D7Fh),FILL(COLOR:Purple),HIDE,LINEWIDTH(1), |
  ROUND
                       STRING('Module'),AT(164,215),USE(?ModuleString),TRN
                       CHECK('Sparse Tree'),AT(213,2,50,10),USE(glo:bShowSparseTrees),HIDE
                       CHECK(' Pro&tected'),AT(160,17,44,8),USE(glo:bShowProtected),COLOR(00E2A981h),TIP('Show Prote' & |
  'cted Attributes'),TRN
                       CHECK(' &Private'),AT(210,17,36,8),USE(glo:bShowPrivate),COLOR(00E2A981h),TIP('Show Priva' & |
  'te Attributes'),TRN
                       CHECK(' &Module'),AT(260,17,36,8),USE(glo:bShowModule),COLOR(00E2A981h),TIP('Show Modul' & |
  'e Attributes'),TRN
                       BOX,AT(8,216,10,8),USE(?EquateBox),COLOR(00B99D7Fh),FILL(COLOR:White),HIDE,LINEWIDTH(1),ROUND
                       IMAGE('efolder.ico'),AT(8,216,10,8),USE(?Equate:Image),CENTERED,HIDE
                       STRING('Grouped'),AT(20,215),USE(?GroupdEquate:String),HIDE,TRN
                       BOX,AT(56,216,10,8),USE(?EnumerationBox),COLOR(00B99D7Fh),FILL(COLOR:White),HIDE,LINEWIDTH(1), |
  ROUND
                       IMAGE('efolder2.ico'),AT(56,216,10,8),USE(?Enumeration:Image),CENTERED,HIDE
                       STRING('Enumerated'),AT(68,215),USE(?EnumeratedEquate:String),HIDE,TRN
                       STRING('Loading...'),AT(196,211,66,14),USE(?LoadingString),FONT('Tahoma',16,COLOR:Navy,FONT:bold, |
  CHARSET:ANSI),TRN
                       STRING('Saving...'),AT(196,211,66,14),USE(?SavingString),FONT('Tahoma',16,COLOR:Navy,FONT:bold, |
  CHARSET:ANSI),HIDE,TRN
                       BUTTON,AT(179,211,14,14),USE(?VcrTop),ICON('VCRFIRST.ICO')
                       BUTTON,AT(193,211,14,14),USE(?VcrRewind),ICON('VCRPRIOR.ICO')
                       BUTTON,AT(207,211,14,14),USE(?VcrBack),ICON('VCRUP.ICO')
                       BUTTON,AT(221,211,14,14),USE(?VcrPlay),ICON('VCRDOWN.ICO')
                       BUTTON,AT(235,211,14,14),USE(?VcrFastForward),ICON('VCRNEXT.ICO')
                       BUTTON,AT(249,211,14,14),USE(?VcrBottom),ICON('VCRLAST.ICO')
                       BUTTON('E&xit'),AT(266,211,45,14),USE(?CloseButton),TIP('Exit the ClassViewer Application')
                       GROUP,AT(30,76,258,58),USE(?RefreshGroup),HIDE
                         BOX,AT(32,78,258,58),USE(?Box5),COLOR(COLOR:Black),FILL(COLOR:Black),LINEWIDTH(1)
                         BOX,AT(30,76,258,58),USE(?Panel7),COLOR(COLOR:Blue),FILL(COLOR:BTNFACE),LINEWIDTH(1)
                         STRING('Building Class Hierarchy'),AT(34,80,252,10),USE(?ProcessString),FONT(,,,FONT:bold, |
  CHARSET:ANSI),CENTER,TRN
                         STRING('Scanning:'),AT(34,119,252,10),USE(?ScanString),CENTER,TRN
                         STRING(@n_4),AT(240,118),USE(glo:lLineNum),HIDE,TRN
                         PANEL,AT(59,91,202,16),USE(?Panel8),BEVEL(-1,-1),FILL(00C8FFFFh)
                         PANEL,AT(59,109,202,6),USE(?Panel8:2),BEVEL(-1,-1),FILL(00C8FFFFh)
                         IMAGE('progress.gif'),AT(60,92,0,14),USE(?ProgressBox),TILED
                         IMAGE('sm_progress.gif'),AT(60,110,0,4),USE(?ProgressBox:2),TILED
                       END
                       IMAGE('tcorner.gif'),AT(311,220),USE(?SizeGrip)
                       BUTTON('?'),AT(1,17,8,8),USE(?BtnTest),SKIP
                     END
   
   CODE
   Message('Hello World','Alert',ICON:Asterisk,BUTTON:Ok)
   RETURN

You can get some code from LibSrc that’s good, like the ABC Classes. I tried thisL

    MEMBER    
    INCLUDE('ABUTIL.INC'),ONCE

MEMBER alone as seen at the top of Class CLW errors mismatched input '\r\n' expecting '('. the spc requires (Parens), so make them optional ()?
This spec | MEMBER LPAREN expr? RPAREN
should be | MEMBER (LPAREN expr? RPAREN)?


The INCLUDE('ABUTIL.INC'),ONCE throws an error 2:4 no viable alternative at input '\r\nINCLUDE'

I think the problem is the includeStmt in down is coreStatement, but an INCLUDE can be almost anywhere … before the MAP, inside it, inside a Module, after it. Same with OMIT() and COMPILE().

As a quick test I added INCLUDE in the “program” and it worked …

program
    : programHeader? lineEnd*
      includeStmt?   //<--- Allow INCLUDE before MAP
      mapSection?

But it does not allow INCLUDE everywhere. How to do that? OMT and COMPILE are not in the spec.

Also, have you tested multiple MAPs?

Hi @RobertoArtigas @CarlBarnes,

Carl, you’re hitting one of the main problems with creating an ANTLR4 grammar for Clarion right on the head here — it’s something I ran into fairly quickly when I originally tried it for the Clarion language extension in VS Code.

Every single quirk across every possible source file really does need to be catered for. Otherwise, any consuming tool (like an editor extension) will simply barf and break as soon as it hits something unexpected in a source file.

I eventually moved on from ANTLR to Tree-sitter, which is supposed to be more forgiving, but even that proved to be a massive undertaking for a single developer. In the end, I actually switched away from Tree-sitter as well and went with my own custom tokenizer/parser because it gave me far more control over Clarion’s many edge cases.

It would be great to see an ANTLR definition created, and I genuinely wish Roberto well with it :slightly_smiling_face: — but it will be a slog. My main suggestion would be to test against every source file in the Clarion LIBSRC directories (both shipped and accessories). ANTLR is extremely unforgiving: it’s relatively easy to get to a “first outline” of a grammar, but getting to a fully tested, production-ready definition is hard work.

Mark

Yes back in post 24 I verified it did not handle it.

The spec mapSection? (lineEnd | declarationSection)* has a “?” that allowed 0 or 1 MAP and required the MAP be before Data.

I suggested the below may allow a mix of “0 to many” i.e. MAP* and Data* mixed, but its not in the last spec:

program
    : programHeader?   //<--- Add ? on End so PROGRAM is optional -------
      lineEnd*         // allow blank lines after PROGRAM
      (                // Group (MAP + DATA)* to allow multiple MAPs mixed with Data
        mapSection*    //change ? to * to allow multiple MAPs
        (lineEnd | declarationSection)*  // allow interleaved blank lines and declarations
      )* 

Greetings - I tried that block that Mr. Carl provided, but it broke the grammar and I have not been able to recover back to something that works. Maybe someone can get that sorted out and posted it back with their test file. Everyone is got the source, test file, and access to the tool. Anyone can give it a shot. I might not able to get back to this for a bit.

I also suspect that Mr. Mark Sarson is correct. It is going to be a slog. Which could explain while I never got an answer from SV about the EBNF form for the parsers. They might have done it by hand. But for less complicated languages, ANTLR seems to be very useful.

Regards

Greetings -
I deleted the old grammar and restarted with the better structure that was provided with the sections. After oodles of time, got to another stuck point. For now, I am going to leave this alone until I get a bit more learned in ANTLR and its possibilities by doing some simpler things as my schedule allows. You have the latest good test and test file, so anyone can pick this up and give it a shot. For now this experiment is complete from my side. I got to do other things. As far as it goes, ChatGPT seems to better used as a helper, if you know the subject domain. There are some things that it does well. Good luck in your experiment.
Regard,
Roberto Artigas