FunctionList classrange question



  • Some additional info.

    Function List parse steps:

    1. The <parser> “commentExpr”-attribute is used to find all the comment code blocks;
    2. The <classRange> “mainExpr”-attribute is used to find all the class code blocks in the none-comment code blocks;
    3. For each class code block found:
      1. The <classRange><className><nameExpr> “expr”-attribute is used to find the classes name;
      2. The <classRange><function> “mainExpr”-attribute is used to find the method definitions;
      3. For each method definition found within the class code block:
        1. The <classRange><function><functionName><funcNameExpr> “expr”-attribute is used to find the method’s name;
        2. The method is added to the trunk of the tree as branch-leaf using class name and method name respectively;
    4. For each remaining code block i.e. neither being a comment nor a class code block:
      1. The <function> “mainExpr”-attribute is used to find the function and method definitions;
      2. For each function/method definition:
        1. The <function><functionName><nameExpr> “expr”-attribute is used to find the function/method’s name;
        2. The <function><className> “expr”-attribute is used to find the function/method’s class name;
        3. The function/method is added to the trunk of the tree as:
          1. a branch-leaf using class name and method name respectively when a class name was found;
          2. a leaf using the function name when no a class name was found;

    ExampleClass.hpp

    class ExampleClass {
      void Method1();
      void Method2() {
        return;
      }
      void Method3();
    }
    void ExampleClass::Method1() {
      return;
    }
    

    Collapsed:

    class ExampleClass {\r\n  void Method1();\r\n  void Method2() {\r\n    return;\r\n  }\r\n  void Method3();\r\n}\r\nvoid ExampleClass::Method1() {\r\n  return;\r\n}\r\n
    
    |<-1------------------------------------------------------------------------------->|                              |<-2------------------------>|
          |<-3------>|                             |<-4---------->|                                                         |<-5------>|  |<-6->|
                                                        |<-7->|
    

    Description for numbered code blocks:

    1. class definition to be matched by <classRange> “mainExpr”-attribute optionally combined with “openSymbol” and “closeSymbol”-attributes;
    2. function definition to be matched by <function> “mainExpr”-attribute;
    3. class name to be matched by <classRange><className><nameExpr> “expr”-attribute;
    4. function definition to be matched by <classRange><function> “mainExpr”-attribute;
    5. class name to be matched by <function><className> “expr”-attribute;
    6. function name to be matched by <function><functionName><nameExpr> “expr”-attribute;
    7. function name to be matched by <classRange><function><functionName><funcNameExpr> “expr”-attribute;

    Result:

    ExampleClass.hpp
    \--- ExampleClass
         +--- Method2
         \--- Method1
    

    Note:
    When the list is unsorted Method2 is listed before Method1 as class code blocks are parsed before any remaining code blocks

    ExampleClass.cpp

    #include "ClassExample.h"
    void HelperFunction() {
      return;
    }
    void ExampleClass::Method3() {
      return;
    }
    

    Collapsed:

    #include "ClassExample.h"\r\nvoid HelperFunction() {\r\n  return;\r\n}\r\nvoid ExampleClass::Method3() {\r\n  return;\r\n}\r\n
    
                                 |<-1----------------->|                      |<-2------------------------>|
                                      |<-3-------->|                               |<-4------>|  |<-5->|
    

    Description for numbered code blocks:

    1. function definition to be matched by <function> “mainExpr”-attribute;
    2. function definition to be matched by <function> “mainExpr”-attribute;
    3. function name to be matched by <function><functionName><nameExpr> “expr”-attribute;
    4. class name to be matched by <function><className> “expr”-attribute;
    5. function name to be matched by <function><functionName><nameExpr> “expr”-attribute;

    Result:

    ExampleClass.hpp
    +--- ExampleClass
    |    \--- Method3
    |
    \--- HelperFunction
    
    


  • That last result should have read ExampleClass.cpp as root label.



  • @MAPJe71
    The parser did not show me the “functions” section and the related functions for me.
    Only showed the following.

    +--- filename.bc
         +--- choice.test.123
         |    +--- before.choice
         |    \--- after.choice
         |
         +--- field.field.123
             \--- on.input
    

    Not sure which part I am missing.
    Reattaching the full <parser> tag what I picked from the above post.

    			<parser
    				displayName="BaanC"
    				id         ="baanc_function"
    				commentExpr="(?x)                                               # free-spacing (see `RegEx - Pattern Modifiers`)
    								(?m-s:\x7C.*$)                                  # Single Line Comment
    							"
    			>
    				<classRange
    					mainExpr="(?x)												# free-spacing (see `RegEx - Pattern Modifiers`)
    							(?im)												# case-insensitive, ^ and $ match at line breaks
    							(?'SECTION'
    								^\h*											# optional leading whitespace at start-of-line
    								(?:												# known section names
    									before\s*\.\s*program
    								|	(?:choice|field)(?:\s*\.\s*\w+)+
    								|	declaration
    								|	functions
    								)
    								\s*:											# end-of-section-header indicator
    							)
    							(?s:.*?)											# whatever, up till
    							(?=(?&amp;SECTION)|\Z)								# ...next section or end-of-text
    						"
    				>
    					<className>
    						<nameExpr expr="^\h*\K\w+(?:\s*\.\s*\w+)*(?=\s*:)" />
    					</className>
    					<function
    						mainExpr="(?x)											# free-spacing (see `RegEx - Pattern Modifiers`)
    								(?im)											# case-insensitive, ^ and $ match at line breaks
    								^\h*											# optional leading whitespace at start-of-line
    								(?:
    									\K											# discard text matched so far
    									\b(?!(?:									# discard known section names
    										before\s*\.\s*program
    									|	(?:choice|field)(?:\s*\.\s*\w+)+
    									|	declaration
    									|	functions
    									)\b)
    									\w+(?:\s*\.\s*\w+)+							# sub-section name
    									\s*:										# end-of-sub-section-header indicator
    								|
    									function\s+
    									(?:extern\s+)?
    									(?:(?:boolean|double|long|string|void|domain\s+[A-Za-z_]\w*)\s+)?
    									\K											# discard text matched so far
    									\w+(?:\s*\.\s*\w+)*							# function name
    									\s*\(										# end-of-function-header indicator
    								)
    							"
    					>
    						<functionName>
    							<funcNameExpr expr="\w+(?:\s*\.\s*\w+)*" />
    						</functionName>
    					</function>
    				</classRange>
    			</parser>
    

    am I missing something?



  • @oirfeodent Make sure there’s an empty line at the end of the .bc file.



  • @MAPJe71
    Still no luck, after adding the last empty line.

    alt text





  • ok, let me check if I have missed something.
    Probably do a fresh install of NPP.

    Regards,



  • @MAPJe71
    Removing the “commentExpr” attribute from the <parser> worked. Thx.

    I have started building the regex to add the other sections and have an additional question.
    For instance, in the <classrange> known section names, if I want to check “before.<anyname>:” main section but should not check “before.choice:|before.checks:” sub section… can it be acheived?

    I tried with

    |	(?:before\.[^checks|choice|delete|display|field|form|group|input|layout|print|read|rewrite|write|zoom|display\.object|new\.object|program])(?:(?:\.)*\w+)+
    

    This doesn’t seem to work. I also tried to create negative look ahead but failed.
    Let me know if you have some suggestions.

    Regards,



  • @oirfeodent
    Do you mean something like

    |	before(?:\s*\.\s*(?!checks|choice|delete|display|field|form|group|input|layout|print|read|rewrite|write|zoom|display\.object|new\.object|program)\w+)+
    


  • @MAPJe71
    The above is close to expected output.
    In the sample file below, the “before.program:” main section gets listed as the sub section of “choice.test.123:” main section.
    Sample file:

    choice.test.123:
    before.choice:
    	funct1(10)
    on.choice:
    	funct1(10)
    
    before.program:
    	set.synchronized.dialog("fxinh0123s000")
    	
    functions:
    function func1(long var1)
    {
        | Do Something 1.
    }
    

    The expected output is

    +--- filename.bc
         +--- choice.test.123:
         |    +--- before.choice
         |    \--- on.choice
         |
         \--- functions:
              \--- func1
    

    But the “before.program:” also gets listed under “choice.test.123:” for the below <classrange> tag.

    				<classRange
    					mainExpr="(?x)												# free-spacing (see `RegEx - Pattern Modifiers`)
    							(?im)												# case-insensitive, ^ and $ match at line breaks
    							(?'SECTION'
    								^\h*											# optional leading whitespace at start-of-line
    								(?:												# known section names
    									after\.(?:(?!choice:|delete:|display:|field:|form\.read:|form:|group:|input:|layout:|program:|read:|receive\.data:|rewrite:|skip\.delete:|skip\.rewrite:|skip\.write:|update\.db\.commit:|write:|zoom:)(?:\.)*\w+)+
    								|	before\.(?:(?!checks:|choice:|delete:|display:|field:|form:|group:|input:|layout:|print:|read:|rewrite:|write:|zoom:|display\.object:|new\.object:|program:)(?:\.)*\w+)+
    								|	(?:choice\.|field\.|zoom\.from\.)(?:(?:\.)*\w+)+
    								|	(?:detail\.|footer\.|form\.|group\.|header\.)(?:\d+)+
    								|	functions
    								|	main\.table\.io
    								)
    								:											# end-of-section-header indicator
    							)
    							(?s:.*?)											# whatever, up till
    							(?=(?&amp;SECTION)|\Z)								# ...next section or end-of-text
    						"
    				>
    					<className>
    						<nameExpr expr="^\h*\K\w+(?:\.\w+)*:" />
    					</className>
    					<function
    						mainExpr="(?x)											# free-spacing (see `RegEx - Pattern Modifiers`)
    								(?im)											# case-insensitive, ^ and $ match at line breaks
    								^\h*											# optional leading whitespace at start-of-line
    								(?:
    									\K											# discard text matched so far
    									\b(?!(?:									# discard known section names
    											after\.(?:(?!choice:|delete:|display:|field:|form\.read:|form:|group:|input:|layout:|program:|read:|receive\.data:|rewrite:|skip\.delete:|skip\.rewrite:|skip\.write:|update\.db\.commit:|write:|zoom:)(?:\.)*\w+)+
    										|	before\.(?:(?!checks:|choice:|delete:|display:|field:|form:|group:|input:|layout:|print:|read:|rewrite:|write:|zoom:|display\.object:|new\.object:|program)(?:\.)*\w+)+
    										|	(?:choice\.|field\.|zoom\.from\.)(?:(?:\.)*\w+)+
    										|	(?:detail\.|footer\.|form\.|group\.|header\.)(?:\d+)+
    										|	functions
    										|	main\.table\.io
    										)\b)
    										\w+(?:\s*\.\s*\w+)+						# sub-section name
    										:										# end-of-sub-section-header indicator
    									|
    										function\s+
    										\K										# discard text matched so far
    										(?:extern\s+)?
    										(?:(?:boolean|double|long|string|void|domain\s+[A-Za-z_]\w*)\s+)?
    										\w+(?:\s*\.\s*\w+)*						# function name
    										\s*\(									# end-of-function-header indicator
    									)
    								"
    					>
    						<functionName>
    							<funcNameExpr expr="(?:extern\s+)?(?:(?:boolean|double|long|string|void|domain\s+[A-Za-z_]\w*)\s+)?\w+(?:\s*\.\s*\w+)*" />
    						</functionName>
    					</function>
    				</classRange>
    

    Adding/removing the ‘:’ to the negative look ahead provides the same results.
    Any possibilities?

    Regards,



  • @oirfeodent Could you provide a complete list of:

    1. valid section names i.e. invalid sub-sections names;
    2. valid sub-section names i.e. invalid section names.


  • Main Sections Sub Sections
    after.<charsDigitsPeriods>.<digitsOnly>: after.choice:
    after.form.read: after.delete:
    after.program: after.display:
    after.receive.data: after.field:
    after.report.<digitsOnly>: after.form:
    after.update.db.commit: after.group:
    before.<charsDigitsPeriods>.<digitsOnly>: after.input:
    before.display.object: after.layout:
    before.new.object: after.read:
    before.program: after.rewrite:
    before.report.<digitsOnly>: after.skip.delete:
    choice.<charsDigitsPeriods>: after.skip.rewrite:
    declaration: after.skip.write:
    detail.<digitsOnly>: after.write:
    field.<charsDigitsPeriods>: after.zoom:
    field.all: before.checks:
    field.other: before.choice:
    footer.<digitsOnly>: before.delete:
    form.<digitsOnly>: before.display:
    form.all: before.field:
    form.other: before.form:
    functions: before.group:
    group.<digitsOnly>: before.input:
    header.<digitsOnly>: before.layout:
    main.table.io: before.print:
    on.display.total.line: before.read:
    on.error: before.rewrite:
    zoom.from.<charsDigitsPeriods>: before.write:
    zoom.from.all: before.zoom:
    zoom.from.other: check.input:
    domain.error:
    init.field:
    init.form:
    init.group:
    on.choice:
    on.entry:
    on.exit:
    on.input:
    read.view:
    ref.display:
    ref.input:
    selection.filter:
    when.field.changes:


  • List of Main Sections:

    Main Sections Has SubSections?
    after.<charsDigitsPeriods>.<digitsOnly>: Atlease one Sub-Section, can have multiple SubSections
    after.form.read: No Subsection
    after.program: No Subsection
    after.receive.data: No Subsection
    after.report.<digitsOnly>: Atlease one Sub-Section, can have multiple SubSections
    after.update.db.commit: No Subsection
    before.<charsDigitsPeriods>.<digitsOnly>: Atlease one Sub-Section, can have multiple SubSections
    before.display.object: No Subsection
    before.new.object: No Subsection
    before.program: No Subsection
    before.report.<digitsOnly>: Atlease one Sub-Section, can have multiple SubSections
    choice.<charsDigitsPeriods>: Atlease one Sub-Section, can have multiple SubSections
    declaration: No Subsection
    detail.<digitsOnly>: Atlease one Sub-Section, can have multiple SubSections
    field.<charsDigitsPeriods>: Atlease one Sub-Section, can have multiple SubSections
    field.all: Atlease one Sub-Section, can have multiple SubSections
    field.other: Atlease one Sub-Section, can have multiple SubSections
    footer.<digitsOnly>: Atlease one Sub-Section, can have multiple SubSections
    form.<digitsOnly>: Atlease one Sub-Section, can have multiple SubSections
    form.all: Atlease one Sub-Section, can have multiple SubSections
    form.other: Atlease one Sub-Section, can have multiple SubSections
    functions: No Subsection, but functions are present
    group.<digitsOnly>: Atlease one Sub-Section, can have multiple SubSections
    header.<digitsOnly>: Atlease one Sub-Section, can have multiple SubSections
    main.table.io: Atlease one Sub-Section, can have multiple SubSections
    on.display.total.line: No Subsection
    on.error: No Subsection
    zoom.from.<charsDigitsPeriods>: Atlease one Sub-Section, can have multiple SubSections
    zoom.from.all: Atlease one Sub-Section, can have multiple SubSections
    zoom.from.other: Atlease one Sub-Section, can have multiple SubSections

    List of Sub Sections

    Sub Sections
    after.choice:
    after.delete:
    after.display:
    after.field:
    after.form:
    after.group:
    after.input:
    after.layout:
    after.read:
    after.rewrite:
    after.skip.delete:
    after.skip.rewrite:
    after.skip.write:
    after.write:
    after.zoom:
    before.checks:
    before.choice:
    before.delete:
    before.display:
    before.field:
    before.form:
    before.group:
    before.input:
    before.layout:
    before.print:
    before.read:
    before.rewrite:
    before.write:
    before.zoom:
    check.input:
    domain.error:
    init.field:
    init.form:
    init.group:
    on.choice:
    on.entry:
    on.exit:
    on.input:
    read.view:
    ref.display:
    ref.input:
    selection.filter:
    when.field.changes:


  • All the sub-sections are definite.
    The main sections inside the <> can be anything based on the description; but has to exist.
    So, “after.<charsDigitsPeriods>.<digitsOnly>:” should end with a “.<digit>:” to be a valid MainSection.
    None of the main sections are mandatory (even functions: main section can be skipped).
    None of the sub sections are mandatory (But atleast one sub-section would exist (Though not mandatory))

    Apart from this, there are two kinds of script.

    1. Regular Script… which will have atleast one of the above sections and optionally the “functions:” sections along with functions.
    2. dll script… which doesn’t have any of the sections, but only functions.

    Sample dll script:

    |This is a dll script, which does not have any sections.
    function extern long func1(long var1)
    {
    	|do something
    }
    
    function void funct2(long var2)
    {
    	|do something
    }
    

    Sample regular script:

    choice.test.123:
    before.choice:
        funct1(10)
    on.choice:
        funct1(10)
    
    before.program:
        func1(10)
        
    functions:
    function func1(long var1)
    {
        | Do Something 1.
    }
    
    

    Regards,



  • @MAPJe71
    The response is multiple replies, as I cant edit the original post. Thx.

    Regards,



  • @oirfeodent Please try the following parser:

    			<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    			|   Based on:
    			|       https://notepad-plus-plus.org/community/topic/14494/functionlist-classrange-question
    			\-->
    			<parser
    				displayName="BaanC Sections v3"
    				id         ="baanc_section"
    			>
    				<classRange
    					mainExpr    ="(?x)                                          # free-spacing (see `RegEx - Pattern Modifiers`)
    							(?im)                                               # case-insensitive, ^ and $ match at line breaks
    							(?(DEFINE)                                          # definition of sub-routines
    								(?'SECTION'
    									^\h*                                        # optional leading whitespace at start-of-line
    									(?:                                         # known section names
    										(?:after|before)\.(?:report\.\d+|\w+(?:\.\w+)*\.\d+)
    									|	(?:field|zoom\.from)\.(?:all|other|\w+(?:\.\w+)*)
    									|	(?:footer|group|header)\.\d+
    									|	choice\.\w+(?:\.\w+)*
    									|	detail\.\d+
    									|	form\.(?:all|other|\d+)
    									|	functions
    									|	main\.table\.io
    									)
    									\h*:                                        # end-of-section-header indicator
    								)
    								(?'SECTION_EMPTY'
    									^\h*                                        # optional leading whitespace at start-of-line
    									(?:                                         # known `empty` section names
    										after\.(?:form\.read|program|receive\.data|update\.db\.commit)
    									|	before\.(?:(?:display|new)\.object|program)
    									|	declaration
    									|	on\.(?:display\.total\.line|error)
    									)
    									\h*:                                        # end-of-section-header indicator
    								)
    							)
    							(?&amp;SECTION)                                     # section header
    							(?s:.*?)                                            # whatever,
    							(?=                                                 # ...up till
    								(?&amp;SECTION)                                 # ...next section header,
    							|	(?&amp;SECTION_EMPTY)                           # ...next `empty` section header
    							|	\Z                                              # ...or end-of-text
    							)
    						"
    				>
    					<className>
    						<nameExpr expr="^\h*\K\w+(?:\.\w+)*\h*:" />
    					</className>
    					<function
    						mainExpr="(?x)                                          # free-spacing (see `RegEx - Pattern Modifiers`)
    								(?im)                                           # case-insensitive, ^ and $ match at line breaks
    								^\h*                                            # optional leading whitespace at start-of-line
    								(?:
    									\K                                          # discard text matched so far
    									(?:                                         # known sub-section names
    										after\.(?:choice|d(?:elete|isplay)|f(?:ield|orm)|group|input|layout|re(?:ad|write)|skip\.(?:delete|(?:re)?write)|write|zoom)
    									|	before\.(?:ch(?:ecks|oice)|d(?:elete|isplay)|f(?:ield|orm)|group|input|layout|print|re(?:ad|write)|write|zoom)
    									|	check\.input
    									|	domain\.error
    									|	init\.(?:f(?:ield|orm)|group)
    									|	on\.(?:choice|e(?:ntry|xit)|input)
    									|	read\.view
    									|	ref\.(?:display|input)
    									|	selection\.filter
    									|	when\.field\.changes
    									)
    									\h*:                                        # end-of-sub-section-header indicator
    								|
    									function\h+
    									(?:extern\h+)?
    									(?:(?:boolean|double|long|string|void|domain\h+[A-Za-z_]\w*)\h+)?
    									\K                                          # discard text matched so far
    									\w+(?:\.\w+)*                               # function name
    									\s*\(                                       # end-of-function-header indicator
    								)
    							"
    					>
    						<functionName>
    							<funcNameExpr expr="\w+(?:\.\w+)*(?:\h*:)?" />
    						</functionName>
    					</function>
    				</classRange>
    				<!--
    				|   Note:
    				|       Having the following `function`-node active will result in all branches
    				|       except the last branch to show their leaves twice in the tree.
    				\-->
    				<function
    					mainExpr="(?x)                                              # free-spacing (see `RegEx - Pattern Modifiers`)
    							(?im)                                               # case-insensitive, ^ and $ match at line breaks
    							^\h*                                                # optional leading whitespace at start-of-line
    							(?:
    								\K                                              # discard text matched so far
    								(?:                                             # known `empty` section names
    									after\.(?:form\.read|program|receive\.data|update\.db\.commit)
    								|	before\.(?:display\.object|new\.object|program)
    								|	declaration
    								|	on\.(?:display\.total\.line|error)
    								)
    								\h*:                                            # end-of-section-header indicator
    							|
    								(?i:function)\h+
    								(?:extern\h+)?
    								(?:(?:boolean|double|long|string|void|domain\h+[A-Za-z_]\w*)\h+)?
    								\K                                              # discard text matched so far
    								\w+(?:\.\w+)*
    								\s*\(
    							)
    						"
    				>
    					<functionName>
    						<nameExpr expr="\w+(?:\.\w+)*(?:\h*:)?" />
    					</functionName>
    				</function>
    			</parser>
    


  • @MAPJe71 said:

                                (?i:function)\h+
                                (?:extern\h+)?
                                (?:(?:boolean|double|long|string|void|domain\h+[A-Za-z_]\w*)\h+)?
                                \K                                              # discard text matched so far
                                \w+(?:\.\w+)*
                                \s*\(
    

    I have changed the \h+ to \s+ so that functions spanning multi-lines are shown properly. Do you see any issues with that?

    Another point is about embedded comments… for below sample

    function extern 	|Test
    long test()
    {
    
    }
    

    if I remove the “|Test” it is shown in the Function List panel… but, with the comment in place it doesn’t show this function.
    So, is there a possibility to check for the presence of comments and ignore the same?

    @MAPJe71 Thx so far for your time and effort.



  • @oirfeodent comments “embedded” in the function/method header are not supported (see also parse steps in earlier post).



  • @MAPJe71
    I thought with the <parser> “commentExpr” -attribute it is not possible to have embedded comments.
    I was playing around with RegexBuddy with the simplest version of the function parser and used the following regex to have the function name highlighted with embedded comments.

    function\s+(\|\w*)*\s+\K\w+(?:\.\w+)*\s*\(
    

    However it failed with the regular function without embedded comment.

    function |TEST
    test()
    {
         |highlighted function name
    }
    
    function test()
    {
          | No highlight. (I guess regex is not correct to handle both)
    }
    

    So, I thought there could be a better way for doing this which I am not aware.
    Hence the question, as the “commentExpr” attribute is not defined.

    If no other way, then also fine. Thx.

    Regards,



  • @oirfeodent new attempt:

    			<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    			|   Based on:
    			|       https://notepad-plus-plus.org/community/topic/14494/functionlist-classrange-question
    			|
    			|   Note(s):
    			|   1.  Boost::Regex 1.58-1.59 do not correctly handle quantifiers on subroutine calls
    			|       therefore the additional non-capturing group i.e. "(?:(?&amp;COMMENT))?" instead
    			|       of simply "(?&amp;COMMENT)?"
    			\-->
    			<parser
    				displayName="BaanC Sections v4.2"
    				id         ="baanc_section"
    			>
    				<classRange
    					mainExpr    ="(?x)                                          # free-spacing (see `RegEx - Pattern Modifiers`)
    							(?im)                                               # case-insensitive, ^ and $ match at line breaks
    							(?(DEFINE)                                          # definition of sub-routines
    								(?'SECTION'
    									^\h*                                        # optional leading whitespace at start-of-line
    									(?:                                         # known section names
    										(?:after|before)\.(?:report\.\d+|\w+(?:\.\w+)*\.\d+)
    									|	(?:field|zoom\.from)\.(?:all|other|\w+(?:\.\w+)*)
    									|	(?:footer|group|header)\.\d+
    									|	choice\.\w+(?:\.\w+)*
    									|	detail\.\d+
    									|	form\.(?:all|other|\d+)
    									|	functions
    									|	main\.table\.io
    									)
    									\h*:                                        # end-of-section-header indicator
    								)
    								(?'SECTION_EMPTY'
    									^\h*                                        # optional leading whitespace at start-of-line
    									(?:                                         # known `empty` section names
    										after\.(?:form\.read|program|receive\.data|update\.db\.commit)
    									|	before\.(?:(?:display|new)\.object|program)
    									|	declaration
    									|	on\.(?:display\.total\.line|error)
    									)
    									\h*:                                        # end-of-section-header indicator
    								)
    							)
    							(?&amp;SECTION)                                     # section header
    							(?s:.*?)                                            # whatever,
    							(?=                                                 # ...up till
    								\s*
    								(?:
    									(?&amp;SECTION)                             # ...next section header,
    								|	(?&amp;SECTION_EMPTY)                       # ...next `empty` section header
    								|	\Z                                          # ...or end-of-text
    								)
    							)
    						"
    				>
    					<className>
    						<nameExpr expr="^\h*\K\w+(?:\.\w+)*\h*:" />
    					</className>
    					<function
    						mainExpr="(?x)                                          # free-spacing (see `RegEx - Pattern Modifiers`)
    								(?im)                                           # case-insensitive, ^ and $ match at line breaks
    								(?(DEFINE)                                      # definition of sub-routines
    									(?'COMMENT'
    										\s*\x7C[^\r\n]*                         # trailing comment
    										(?:                                     # optional subsequent comment
    											(?:\r?\n|\n?\r)                     # - mandatory line-break
    											\s*\x7C[^\r\n]*                     # - `trailing` comment
    										)*
    									)
    								)
    								^\h*                                            # optional leading whitespace at start-of-line
    								(?:
    									\K                                          # discard text matched so far
    									(?:                                         # known sub-section names
    										after\.(?:choice|d(?:elete|isplay)|f(?:ield|orm)|group|input|layout|re(?:ad|write)|skip\.(?:delete|(?:re)?write)|write|zoom)
    									|	before\.(?:ch(?:ecks|oice)|d(?:elete|isplay)|f(?:ield|orm)|group|input|layout|print|re(?:ad|write)|write|zoom)
    									|	check\.input
    									|	domain\.error
    									|	init\.(?:f(?:ield|orm)|group)
    									|	on\.(?:choice|e(?:ntry|xit)|input)
    									|	read\.view
    									|	ref\.(?:display|input)
    									|	selection\.filter
    									|	when\.field\.changes
    									)
    									\h*:                                        # end-of-sub-section-header indicator
    								|
    									function                                    # keyword, start-of-function-header indicator
    									(?:(?&amp;COMMENT))?                        # optional `embedded` comment
    									(?:                                         # optional storage-class specifier
    										\s+extern
    										(?:(?&amp;COMMENT))?                    # ...with optional `embedded` comment
    									)?
    									(?:                                         # optional function type specifier
    										\s+(?:boolean|double|long|string|void|domain\h+[A-Za-z_]\w*)
    										(?:(?&amp;COMMENT))?                    # ...with optional `embedded` comment
    									)?
    									\s+
    									\K                                          # discard text matched so far
    									\w+(?:\.\w+)*                               # function identifier
    									(?:(?&amp;COMMENT)(?:\r?\n|\n?\r))?         # optional `embedded` comment
    									\s*\(                                       # start-of-parameter-list indicator
    								)
    							"
    					>
    						<functionName>
    							<funcNameExpr expr="\w+(?:\.\w+)*(?:\h*:)?" />
    						</functionName>
    					</function>
    				</classRange>
    				<function
    					mainExpr="(?x)                                              # free-spacing (see `RegEx - Pattern Modifiers`)
    							(?im)                                               # case-insensitive, ^ and $ match at line breaks
    							(?(DEFINE)                                          # definition of sub-routines
    								(?'COMMENT'
    									\s*\x7C[^\r\n]*                             # trailing comment
    									(?:                                         # optional subsequent comment
    										(?:\r?\n|\n?\r)                         # - mandatory line-break
    										\s*\x7C[^\r\n]*                         # - `trailing` comment
    									)*
    								)
    							)
    							^\h*                                                # optional leading whitespace at start-of-line
    							(?:
    								\K                                              # discard text matched so far
    								(?:                                             # known `empty` section names
    									after\.(?:form\.read|program|receive\.data|update\.db\.commit)
    								|	before\.(?:display\.object|new\.object|program)
    								|	declaration
    								|	on\.(?:display\.total\.line|error)
    								)
    								\h*:                                            # end-of-section-header indicator
    							|
    								function                                        # keyword, start-of-function-header indicator
    								(?:(?&amp;COMMENT))?                            # optional `embedded` comment
    								(?:                                             # optional storage-class specifier
    									\s+extern
    									(?:(?&amp;COMMENT))?                        # ...with optional `embedded` comment
    								)?
    								(?:                                             # optional function type specifier
    									\s+(?:boolean|double|long|string|void|domain\h+[A-Za-z_]\w*)
    									(?:(?&amp;COMMENT))?                        # ...with optional `embedded` comment
    								)?
    								\s+
    								\K                                              # discard text matched so far
    								\w+(?:\.\w+)*                                   # function identifier
    								(?:(?&amp;COMMENT)(?:\r?\n|\n?\r))?             # optional `embedded` comment
    								\s*\(                                           # start-of-parameter-list indicator
    							)
    						"
    				>
    					<functionName>
    						<nameExpr expr="\w+(?:\.\w+)*(?:\h*:)?" />
    					</functionName>
    				</function>
    			</parser>
    

Log in to reply