Predefined functions:

Function name

Occurence

charAt(...)

39

composeHTMLLikeString(...)

7

endString(...)

9

endl(...)

19

existVariable(...)

11

findElement(...)

2

findFirstChar(...)

39

first(...)

12

getFloatingLocation(...)

23

getMarkupKey(...)

1

getProperty(...)

3

getWorkingPath(...)

11

isEmpty(...)

6

isNegative(...)

39

newFloatingLocation(...)

12

not(...)

72

startString(...)

39

subString(...)

39

toUpperString(...)

39

Procedures:

Instruction name

Occurence

__RAW_TEXT_TO_WRITE(...)

498

clearVariable(...)

1

expand(...)

1

generate(...)

9

insertTextOnce(...)

24

parseAsBNF(...)

1

setCommentBegin(...)

1

setCommentEnd(...)

1

setProtectedArea(...)

19

traceLine(...)

5

translate(...)

1

writeText(...)

325

File "GettingStarted/CppObjectBody.cwt":


   
//note: Visual C++-specific pragma must be added to prevent from intempestive warnings
   
//note: about template class instantiation of \samp{std::vector<\textit{T}>} in DEBUG mode!
   
#ifdef WIN32
   
#pragma warning(disable : 4786)
   
#endif
   

   
@
   
//note: the developer will add here all include files he will need for implementation of
   
//note: methods,
[3]
setProtectedArea("include files");
   
@
   
#include "@
   
//note: the header of this body is compulsory,
   
//merge:
[3]
this.name@.h"
   

[3]
@this.name@::@this.name@()@
   
//note: this part concerns the initialization of attributes. Some attributes, such as strings
   
//note: and vectors of the STL don't require to be initialized explicitly. It justifies the
   
//note: declaration of variable \samp{bAtLeastOne} that is worth \samp{false} as long as
   
//note: no attribute has been initialized yet. We'll see why below.
[3]
local bAtLeastOne = false;
[3]
foreach i in this.listOfAttributes {
   
//note: arrays and strings are skipped,
[1]
    if !i.type.isArray && (i.type.name != "string") {
   
        if bAtLeastOne {
   
//note: if it isn't the first attribute to be initialized, a comma make a separation with
   
//note: the precedent,
   
            @, @
[1]
        } else {
   
//note: if it is the first attribute to be initialized, a colon is expected to announce
   
//note: the beginning of initializations
   
            @ : @
   
//note: now, there is at least one attribute to be initialized,
[1]
            set bAtLeastOne = true;
   
        }
[1]
        @_@getVariableName(i.name, i.type)@(@
   
//note: attribute is populated with the default value corresponding to its type,
   
        if i.type.isObject {
   
            @0L@
[1]
        } else {
[1]
            switch(i.type.name) {
   
                case "int":
   
                    @0@
   
                    break;
   
                case "double":
   
                    @0.0@
[1]
                    break;
   
                case "boolean":
   
                    @false@
   
                    break;
   
            }
   
        }
   
        @)@
   
    }
   
}
   
@ {
   
}
   

[3]
@this.name@::~@this.name@() {
   
@
   
//note: aggregated objects must be deleted before leaving this instance,
[3]
foreach i in this.listOfAttributes {
[1]
    if i.type.isAggregation && i.type.isObject {
[1]
        local sAttributeName = "_" + getVariableName(i.name, i.type);
[1]
        local sIndex = "iterate" + normalizeIdentifier(i.name);
[1]
        if i.type.isArray {
   
//note: all elements of an aggregated array must be deleted
[1]
            @ for (std::vector<@i.name@*>::const_iterator @sIndex@ = @sAttributeName@.begin(); @sIndex@ != @sAttributeName@.end(); ++@sIndex@) {
[1]
        delete *@sIndex@;
   
    }
   
@
   
        } else {
   
//note: the aggregated object is deleted
   
            @ delete @sAttributeName@;
   
@
   
        }
   
    }
   
}
   
@}
   

   
@
   
//note: implementation of all methods,
[3]
foreach i in this.listOfMethods {
   
//note: the return type of the method is translated to C++,
[1]
    if existVariable(i.type) {
[1]
        @@getType<"C++">(i.type)@@
   
    } else {
   
        @void@
   
    }
[1]
    @ @this.name@::@i.name@(@
   
//note: parameters of the method are iterated to be written in C++
[1]
    foreach j in i.listOfParameters {
   
//note: if iterator \samp{j} doesn't point to the first parameter, a comma makes a
   
//note: separation with the precedent,
[2]
        if !first(j) {
   
            @, @
   
        }
[3]
        @@getParameterType<"C++">(j.type, j.mode)@ @getVariableName(j.name, j.type)@@
   
    }
   
    @) {
   
@
   
//note: a protected area is inserted, whose key is the method ID,
[1]
        setProtectedArea(getMethodID(i));
   
@}
   
@
   
}

File "GettingStarted/CppObjectHeader.cwt":

User defined function

Occurence

Time in ms

populateHeaderDeclarations(...) at 29

7

0


   
#ifndef _@
   
//note: the value of attribute \samp{\textit{this.}name} is written to the output file, where
   
//note: \samp{\textit{this}} points to a node that describes the current class. Note that
   
//note: \samp{\textit{this}} is facultative, and is assigned by the caller of procedure
   
//note: \samp{generate} that runs this script.
   
//merge:
[3]
this.name@_h_
[3]
#define _@this.name@_h_
   

   
@
   
//note: put one anchor for including all files that we'll encounter as compulsory, while
   
//note: iterating attributes or methods. Example: if an attribute is an array, we'll need
   
//note: to include the STL header \textit{vector} at this position of the file:
   
//note: \textit{\#include }. This insertion point is called \samp{"include files"}.
[3]
newFloatingLocation("include files");
   
//note: to avoid that the two floating locations \samp{"include files"} and \samp{"class declarations"}
   
//note: (described just below) point to the same file position, an empty line is added,
   
@
   
// this line separates the two insertion points, so as to distinguish them!
   
@
   
//note: put one anchor for announcing all classes that we'll encounter as referenced, while
   
//note: iterating attributes or methods. Example: if an attribute is an object
   
//note: \textit{Planet}, we'll need to write \textit{class Planet;} at this position of
   
//note: the file. This insertion point is called \samp{"class declarations"}.
[3]
newFloatingLocation("class declarations");
   

   
//note: this function is called on every type encountered while iterating attributes and methods.
   
//note: Its role is to populate the \samp{"include files"} and \samp{"class declarations"} areas.
[7]
function populateHeaderDeclarations(myType : node) {
   
//note: the type of an object must be declared at the beginning of the header, otherwise
   
//note: the compiler will not recognize it : the class is declared \textbf{once only} in
   
//note: the insertion point called \samp{"class declarations"}. Use of function \samp{insertTextOnce}
   
//note: assures that if this class has already been inserted before, it will not be twice.
[1]
    if myType.isObject insertTextOnce(getFloatingLocation("class declarations"), "class " + myType.name + ";" + endl());
   
//note: this type is an array, so the declaration of \samp{std::vector} must be included
   
//note: to the insertion point called \samp{"include files"},
[2]
    if myType.isArray insertTextOnce(getFloatingLocation("include files"), "#include " + endl());
   
//note: this type is a string, so the declaration of \samp{std::string} must be included
   
//note: to the insertion point called \samp{"include files"},
[7]
    if myType.name insertTextOnce(getFloatingLocation("include files"), "#include " + endl());
   
}
   

   
@
[3]
class @this.name@ @
   
//note: if the class inherits from a parent class, this relationship must be written,
[1]
if existVariable(this.parent) {
   
//note: the parent class must be declared,
[1]
    insertTextOnce(getFloatingLocation("include files"), "#include \"" + this.parent.name +".h\"" + endl());
[1]
    @: public @this.parent.name@ @
   
}
   
@{
   
    private:
   
@
   
//note: declaration of all attributes,
[3]
foreach i in this.listOfAttributes {
   
//note: does the type of the attribute need some backward declarations?
[3]
    populateHeaderDeclarations(i.type);
[3]
    @ @getType<"C++">(i.type)@ _@getVariableName(i.name, i.type)@;
   
@
   
}
   
@
   
    public:
[3]
        @this.name@();
[3]
        ~@this.name@();
   

   
        // accessors:
   
@
   
//note: accessors to each attribute,
[3]
foreach i in this.listOfAttributes {
[3]
    local sVariableName = getVariableName(i.name, i.type);
   
//note: there are two symbols to swap between writing a sequence of characters and
   
//note: interpreting script ; we have used the symbol \textbf{'@'}, and now we illustrate
   
//note: the use of tags \textbf{'<\%} and \textbf{'\%>},
[3]
    %> inline <%getType<"C++">(i.type)%> get<%normalizeIdentifier (i.name)%>() const { return _<%sVariableName%>; }
   
        inline void set<%
   
//note: you can melt the two swapping symbol, but it is more difficult to read, so not
   
//note: very interesting!
   
//merge:
[3]
normalizeIdentifier(i.name)@(<%getType <"C++">(i.type)%> <%sVariableName@) { _<%sVariableName%> = <%sVariableName%>; }
   
@
   
}
   
@
   
        // methods:
   
@
   
//note: declaration of all methods,
[3]
foreach i in this.listOfMethods {
   
//note: each method might be overloaded by subclasses,
   
    @ virtual @
   
//note: the return type of the method is translated to C++,
[1]
    if existVariable(i.type) {
   
//note: does the return type of the method need some backward declarations?
[1]
        populateHeaderDeclarations(i.type);
   
//note: expression \samp{getType<"C++">(i.type)} to evaluate is embedded between double
   
//note: \textbf{'@'}. The first one allow swapping to the \textit{sequence of characters}
   
//note: mode, but there is no characters to write. The second one allows swapping to the
   
//note: \textit{script} mode, which is reduced just to evaluate the expression. The two
   
//note: final \textbf{'@'} take the same role as seen before.
[1]
        @@getType<"C++">(i.type)@@
   
    } else {
   
        @void@
   
    }
[1]
    @ @i.name@(@
   
//note: parameters of the method are iterated to be written in C++
[1]
    foreach j in i.listOfParameters {
   
//note: if iterator \samp{j} doesn't point to the first parameter, a comma makes a
   
//note: separation with the precedent,
[2]
        if !first(j) {
   
            @, @
   
        }
   
//note: does the type of the parameter need some backward declarations?
[3]
        populateHeaderDeclarations(j.type);
[3]
        @@getParameterType<"C++">(j.type, j.mode)@ @getVariableName(j.name, j.type)@@
   
    }
   
    @);
   
@
   
}
   
@
   
    private:
[3]
        @this.name@(const @this.name@&);
[3]
        @this.name@& operator =(const @this.name@&);
   
};
   

   
#endif

File "GettingStarted/HTML2LaTeX.cwp":


   
#noCase
   

[1]
HTML2LaTeX ::= #ignore(HTML) #continue '<' "HTML" '>' HTMLHeader HTMLBody '<' '/' "HTML" '>' #empty;
   
HTMLHeader ::= '<' #continue "HEAD" '>' [~['<' '/' "HEAD" '>']]* '<' '/' "HEAD" '>';
   
HTMLBody ::= '<' #continue "BODY" '>' HTMLText '<' '/' "BODY" '>';
   
//note: blank characters are interesting, so we refuse to ignore HTML blanks and comments,
   
HTMLText ::= #!ignore
   
        [
   
//note: handling of HTML escape sequences, announced by character \textbf{'\&'},
   
            '&' #continue #readIdentifier:sEscape HTMLEscape ';'
   
                |
   
//note: if not the beginning of a tag, the current character of the input stream
   
//note: is put to the output stream,
   
            ~'<':cChar => writeText(cChar);
   
                |
   
//note: token operator '!' doesn't move the position of the input stream, and it continues
   
//note: in sequence only if the token expression that follows doesn't match; here, we check
   
//note: whether we have reached an end of tag or not,
   
            !['<' blanks '/']
   
            [
   
//note: we do not ignore comments anymore, so we have to do it my ourselves,
   
                ""]* "-->"
   
                    |
   
//note: an embedded tag has been encountered,
   
                '<' #continue #ignore(HTML) #readIdentifier:sTag HTMLNextOfTag
   
            ]
   
        ]*;
   
//note: template clauses \samp{HTMLEscape<\textit{T}>} are always valid and just convert
   
//note: special characters to their LaTeX representation,
   
HTMLEscape<"lt"> ::= => {@<@};
   
HTMLEscape<"gt"> ::= => {@>@};
   
HTMLTag(sTag : value) ::= '<' #readText(sTag) #continue HTMLNextOfTag;
   
//note: in the real life, HTML tag \textit{

} could represent a chapter, but the LaTeX
   
//note: output file is intended to be included into the reference manual of \CodeWorker\ as
   
//note: an illustration ; it will be a part of a section, so chapters are translated as
   
//note: sub sections!
   
HTMLNextOfTag<"H1"> ::=
   
        #continue '>' => {@\subsection{@}
   
        HTMLText
   
        '<' '/' "H1" '>' => {@}@};
   
//note: in the real life, HTML tag \textit{

} could represent a section, but for the same
   
//note: reason as above, it will be translated as a sub-sub section,
   
HTMLNextOfTag<"H2"> ::=
   
        #continue '>' => {@\subsubsection{@}
   
        HTMLText
   
        '<' '/' "H2" '>' => {@}@};
   
HTMLNextOfTag<"A"> ::= [HTMLAttribute]* #continue '>' HTMLText '<' '/' 'A' '>';
   
HTMLNextOfTag<"TABLE"> ::=
   
        [HTMLAttribute]* #continue '>' => {
   
            @\begin{table@
   
//note: with HTML, the number of columns the table expects is deduced later. However, a
   
//note: latex table (well-formed for a PDF conversion) must know explicetly of how many
   
//note: columns it is composed. So, a floating position is attached to the current position
   
//note: of the output file. While discovering columns, text will be inserted here and further.
   
            newFloatingLocation("table PDF suffix");
   
            @}{@
   
//note: the format of each column is specified at this place,
   
            newFloatingLocation("table columns");
   
            @}{.5}@
   
        }
   
//note: we consider that the first line of the table gives the name of the columns, and we'll
   
//note: take the PDF table suffix ('ii' for 2 columns, 'iii' for 3 columns, ...) to write
   
//note: lines of the table correctly,
   
        => local sPDFTableSuffix;
   
        HTMLTableTitle(sPDFTableSuffix)
   
//note: we translate as many lines of the table as we can read, knowing the PDF suffix,
   
        [HTMLTableLine(sPDFTableSuffix)]*
   
        '<' '/' "TABLE" '>' => {@\end{table@sPDFTableSuffix@}
   
@};
   
HTMLTableTitle(sPDFTableSuffix : node) ::=
   
    '<' "TR" [HTMLAttribute]*
   
    #continue '>'
   
    [HTMLTableCol(sPDFTableSuffix)]*
   
    '<' '/' "TR" '>' => {
   
        insertText(getFloatingLocation("table PDF suffix"), sPDFTableSuffix);
   
        writeText(endl());
   
    };
   
//note: the clause is intended to read the name of a column of a table, and to translate it
   
//note: to LaTeX, knowing that some text must be inserted into the declarative part of the
   
//note: LaTeX table,
   
HTMLTableCol(sPDFTableSuffix : node) ::=
   
    '<' "TD" [HTMLAttribute]* #continue '>' => {
   
        @{@
   
        if !sPDFTableSuffix insertText(getFloatingLocation("table columns"), "l");
   
        else insertText(getFloatingLocation("table columns"), "|l");
   
        set sPDFTableSuffix += "i";
   
    }
   
    '<' 'B' '>' [#!ignore [~'<':cChar => writeText(cChar);]*] '<' '/' 'B' '>'
   
    '<' '/' "TD" '>' => {@}@};
   
HTMLTableLine(sPDFTableSuffix : value) ::=
   
        '<' "TR" [HTMLAttribute]* #continue '>' => {@\line@sPDFTableSuffix@@}
   
        [HTMLTag("TD")]* '<' '/' "TR" '>' => {writeText(endl());};
   
HTMLNextOfTag<"TD"> ::=
   
        [HTMLAttribute]* #continue '>' => {@{@}
   
        HTMLCellText '<' '/' "TD" '>' => {@}@};
   
//note: the text into a cell of a table shouldn't contain paragraph jumps (empty line in LaTeX),
   
HTMLCellText ::= #!ignore
   
        [
   
            '&' #continue #readIdentifier:sEscape HTMLEscape ';'
   
                |
   
//note: the simplest way to avoid empty lines is to ignore end of lines, and to replace it to
   
//note: a space,
   
            ['\r']? ['\n'] => {@ @}
   
                |
   
            ~'<':cChar => writeText(cChar);
   
                |
   
            !['<' blanks '/']
   
            [
   
                ""]* "-->"
   
                    |
   
                '<' #continue #ignore(HTML) #readIdentifier:sTag HTMLNextOfTag
   
            ]
   
        ]*;
   
HTMLNextOfTag<"UL"> ::=
   
        [HTMLAttribute]* #continue '>' => {@\begin{itemize}
   
@}
   
        [HTMLTag("LI")]*
   
        '<' '/' "UL" '>' => {@\end{itemize}
   
@};
   
HTMLNextOfTag<"LI"> ::=
   
        [HTMLAttribute]* #continue '>' => {@\item @}
   
        HTMLText
   
        '<' '/' "LI" '>' => {writeText(endl());};
   
HTMLNextOfTag<"B"> ::=
   
        #continue '>' => {@\textbf{@}
   
        HTMLText
   
        '<' '/' "B" '>' => {@}@};
   
HTMLNextOfTag<"I"> ::=
   
        #continue '>' => {@\textbf{@}
   
        HTMLText
   
        '<' '/' "I" '>' => {@}@};
   
HTMLNextOfTag<"FONT"> ::= [HTMLAttribute]* #continue '>' HTMLText '<' '/' "FONT" '>';
   
HTMLNextOfTag<"BR"> ::= ['/']? #continue '>' => { writeText(endl());};
   
HTMLAttribute ::= #readIdentifier ['=' #continue [STRING_LITERAL | WORD_LITERAL]]?;
   

   

   
blanks ::= [' '| '\t' | '\r' | '\n']*;
   
STRING_LITERAL ::= #!ignore '\"' [~'\"']* '\"';
   
WORD_LITERAL ::= #!ignore [~['>' | '/' | ' ' | '\t']]+;

File "GettingStarted/HTMLDocumentation.cwt":


   
@
   
//note: the predefined function \samp{getMarkupKey()} returns the name of the markup
   
//note: to expand,
[1]
if getMarkupKey() == "classes presentation" {
   
//note: the markup is worth "classes presentation", and so, we'll describe all classes
[1]
    foreach i in project.listOfClasses {
   
        @
[3]
        

@i.name@


   
@
   
//note: a protected area is embedded here, which has to be populated by hand into the
   
//note: expanded file for describing the class,
[3]
        setProtectedArea(i.name + ":presentation");
[3]
        if !isEmpty(i.listOfAttributes) {
   
//note: attributes are presented into a table,
   
            @
   
        
   
            
   
                
   
                
   
                
   
            
   
@
[3]
            foreach j in i.listOfAttributes {
   
//note: the language into which types have to be expressed is given by \samp{this.language},
   
//note: and is worth "C++" or "JAVA" ; don't forget to convert the type to the HTML syntax,
   
//note: because of \textbf{'<'} or \textbf{'>'} to convert respectively to \textbf{'\<'}
   
//note: or \textbf{'\>'} for instance. Use the predefined function
   
//note: \samp{composeHTMLLikeString()} to do this process.
   
                @
[3]
                
[3]
                
   
                
   
            
   
@
   
            }
   
            @
Type Attribute name Description
@composeHTMLLikeString(getType (j.type))@ @j.name@
   
@
   
//note: a protected area is embedded here, which has to be populated by hand into the
   
//note: expanded file for describing the attribute,
[3]
                setProtectedArea(i.name + "::" + j.name + ":description");
   
                @
   
                

   
@
   
        }
[1]
        if !isEmpty(i.listOfMethods) {
   
            @
   
        
   
@
   
        }
   
    }
   
}

File "GettingStarted/JAVAObject.cwt":


   
package solarsystem;
   

[3]
public class @this.name@ @
   
//note: if the class inherits from a parent class, this relationship must be written,
[1]
if existVariable(this.parent) {
[1]
    @extends @this.parent.name@ @
   
}
   
@{
   
@
   
//note: declaration of all attributes,
[3]
foreach i in this.listOfAttributes {
[3]
    @ private @getType<"JAVA">(i.type)@ _@getVariableName(i.name, i.type)@;
   
@
   
}
   
@
[3]
    public @this.name@() {}
   

   
    // accessors:
   
@
   
//note: accessors to each attribute,
[3]
foreach i in this.listOfAttributes {
[3]
    local sVariableName = getVariableName(i.name, i.type);
[3]
    @ public @getType<"JAVA">(i.type)@ get@normalizeIdentifier(i.name)@() { return _@sVariableName@; }
[3]
    public void set@normalizeIdentifier(i.name)@(@getType<"JAVA">(i.type)@ @sVariableName@) { _@sVariableName@ = @sVariableName@; }
   
@
   
}
   
@
   
        // methods:
   
@
   
//note: declaration of all methods,
[3]
foreach i in this.listOfMethods {
   
    @ public @
[1]
    if existVariable(i.type) {
[1]
        @@getType<"JAVA">(i.type)@@
   
    } else {
   
        @void@
   
    }
[1]
    @ @i.name@(@
[1]
    foreach j in i.listOfParameters {
[2]
        if !first(j) {
   
            @, @
   
        }
[3]
        @@getParameterType<"JAVA">(j.type, j.mode)@ @getVariableName(j.name, j.type)@@
   
    }
   
    @) {
   
@
[1]
    setProtectedArea(getMethodID(i));
   
@ }
   

   
@
   
}
   
@}

File "GettingStarted/LeaderScript6.cws":


   
//command: -I Scripts/Tutorial -path .
   
//command: -define DESIGN_FILE=GettingStarted/SolarSystem0.sml
   
//command: -script GettingStarted/LeaderScript6.cws
   
//command: -quantify Scripts/Tutorial/GettingStarted/quantify.html
[1]
if !getProperty("DESIGN_FILE")
   
    error("'-define DESIGN_FILE=file' expected on the command line");
[1]
traceLine("'Simple Modeling' design file to parse = \""
   
          + getProperty("DESIGN_FILE") + "\"");
   
//hide:
[1]
clearVariable(project.listOfClasses);
[1]
parseAsBNF("GettingStarted/SimpleML-parsing.cwp",
   
           project, getProperty("DESIGN_FILE"));
   
#include "TreeDecoration.cws"
   

   
#include "SharedFunctions.cws"
[1]
foreach myClass in project.listOfClasses {
[3]
    traceLine("generating class '" + myClass.name + "' ...");
[3]
    generate("GettingStarted/CppObjectHeader.cwt", myClass, getWorkingPath() + "Scripts/Tutorial/GettingStarted/Cpp/" + myClass.name + ".h");
[3]
    generate("GettingStarted/CppObjectBody.cwt", myClass, getWorkingPath() + "Scripts/Tutorial/GettingStarted/Cpp/" + myClass.name + ".cpp");
[3]
    generate("GettingStarted/JAVAObject.cwt", myClass, getWorkingPath() + "Scripts/Tutorial/GettingStarted/JAVA/solarsystem/" + myClass.name + ".java");
   
}
   

[1]
local myDocumentationContext;
[1]
insert myDocumentationContext.language = "C++";
[1]
traceLine("generating the HTML documentation...");
[1]
setCommentBegin("");
[1]
expand("GettingStarted/HTMLDocumentation.cwt",
   
        myDocumentationContext, getWorkingPath()
   
        + "Scripts/Tutorial/GettingStarted/SolarSystem1.html");
[1]
translate("GettingStarted/HTML2LaTeX.cwp", project, "GettingStarted/SolarSystem1.html", getWorkingPath() + "Scripts/Tutorial/GettingStarted/SolarSystem.tex");

File "GettingStarted/SimpleML-parsing.cwp":


   
// syntactical clauses:
   
//note: the pattern \textit{[class_declaration]*} always matches with the parsed file,
   
//note: so the rule will continue in sequence in any case (supposing that no error has
   
//note: occurred into clause \textit{class_declaration}) and the end of file will be
   
//note: checked. If not reached, it doesn't write the message \samp{"file read successfully"},
[1]
world ::= #ignore(C++) [class_declaration]* #empty
   
            => {
   
                traceLine("file parsed successfully");
   
                saveProject("Scripts/Tutorial/SolarSystem0.xml");
   
            };
   
//note: once keyword \samp{"class"} has been matched, there is no ambiguity : we are
   
//note: handling a class declaration and the rule must continue in sequence. To require
   
//note: that, instruction \samp{\#continue} is written after pattern \samp{"class"}.
   
//note: If a pattern of the sequence doesn't match the parsed file, the parser throws
   
//note: a syntax error automatically.
   
class_declaration ::= IDENT:"class" #continue
   
//note: the identifier that matches with clause call \textit{IDENT} is assigned to
   
//note: the local variable \samp{sClassName} : on contrary of other types of script,
   
//note: a new variable is considered as local, instead of an new attribute added to
   
//note: the current node \samp{\textbf{this}},
   
            IDENT:sClassName
   
//note: about parsing, classes are modeled into node
   
//note: \textbf{project.listOfClasses[}\textit{sClassName}\textbf{]}. Its attribute
   
//note: \samp{name} contains the value of \textit{sClassName}.
   
                => insert project.listOfClasses[sClassName].name = sClassName;
   
//note: if the class inherits from a parent, \samp{\textbf{':'}} is necessary followed by
   
//note: an identifier (pattern \samp{\#continue}), and the identifier that matches with
   
//note: clause call \textit{IDENT} is assigned to the local variable \samp{sClassName},
   
            [':' #continue IDENT:sParentName
   
//note: this class inherits from a parent, so the optional attribute \samp{parent}
   
//note: of the class is populated with the value of \textit{sParentName},
   
                => insert project.listOfClasses[sClassName].parent = sParentName;
   
            ]?
   
            class_body(project.listOfClasses[sClassName]);
   
//note: clause \samp{class_body} expects an argument: the class node into which the
   
//note: class members must be described (\samp{myClass : \textbf{node}}),
   
class_body(myClass : node) ::= '{'
   
        [attribute_decl(myClass) | method_decl(myClass)]* '}';
   
//note: the class is populated with the characteristics of the attribute once
   
//note: its declaration has finished. Otherwise, it may confuse with the beginning
   
//note: of a method declaration. To avoid this ambiguity, we should have factorized
   
//note: the type declaration and the name of the member into a common clause, for
   
//note: example.
   
attribute_decl(myClass : node) ::=
   
            => local myType;
   
            type_specifier(myType) IDENT:sAttributeName ';'
   
            => {
   
//note: about parsing, attributes are modeled into node
   
//note: \textbf{myClass.listOfAttributes[}\textit{sAttributeName}\textbf{]},
   
                insert myClass.listOfAttributes[sAttributeName].name = sAttributeName;
   
//note: the type is allocated on the stack, so it is copied into branch \samp{type}
   
//note: (no node reference) integrally,
   
                setall myClass.listOfAttributes[sAttributeName].type = myType;
   
            };
   
//note: the class is populated with the characteristics of the method once
   
//note: the opened parenthesis is recognized,
   
method_decl(myClass : node) ::=
   
            => local myType;
   
            [IDENT:"void" | type_specifier(myType)]
   
            IDENT:sMethodName '('
   
//note: from here, there is no doubt that we are parsing a method declaration,
   
            #continue
   
                => {
   
//note: about parsing, methods are modeled into node
   
//note: \textbf{myClass.listOfMethods[}\textit{sMethodName}\textbf{]},
   
                    insert myClass.listOfMethods[sMethodName].name = sMethodName;
   
//note: attribute \samp{name} is compulsory into a \textit{type} node, so if
   
//note: condition \samp{myType.name} returns \samp{false}, there is no return
   
//note: type (\samp{void}),
   
                    if myType.name
   
                        setall myClass.listOfMethods[sMethodName].type = myType;
   
                }
   
            [parameters_decl(myClass.listOfMethods[sMethodName])]? ')' ';';
   
parameters_decl(myMethod : node) ::=
   
                parameter(myMethod)
   
//note: a parameter declaration is expected after the comma,
   
                [',' #continue parameters_decl(myMethod)]*;
   
parameter(myMethod : node) ::=
   
            [parameter_mode]?:sMode
   
            => local myType;
   
            type_specifier(myType)
   
            IDENT:sParameterName
   
                => {
   
//note: about parsing, parameters are modeled into node
   
//note: \textbf{myMethod.listOfParameters[}\textit{sParameterName}\textbf{]},
   
                    insert myMethod.listOfParameters[sParameterName].name = sParameterName;
   
                    setall myMethod.listOfParameters[sParameterName].type = myType;
   
                    if sMode {
   
                        insert myMethod.listOfParameters[sParameterName].name = sMode;
   
                    }
   
                };
   
parameter_mode ::= IDENT:{"in", "inout", "out"};
   
type_specifier(myType : node) ::=
   
    basic_type(myType)
   
//note: about parsing, \textbf{myType.isArray} contains \samp{true} if type is an array,
   
    ['[' #continue ']' => insert myType.isArray = true; ]?;
   
basic_type(myType : node) ::=
   
//note: about parsing, \textbf{myType.name} contains the name of basic type,
   
    ["int" | "boolean" | "double" | "string"]:myType.name
   
        |
   
    class_specifier(myType);
   
class_specifier(myType : node) ::=
   
//note: about parsing, \textbf{myType.isAggregation} contains \samp{true} if
   
//note: the object is aggregated,
   
    ["aggregate" => insert myType.isAggregation = true; ]?
   
//note: about parsing, \textbf{myType.isObject} contains \samp{true} because
   
//note: this type is a class specifier,
   
    IDENT:myType.name => {insert myType.isObject = true; };
   

   
//note: the lexical clause \textit{IDENT} recognizes identifiers and might be replaced by
   
//note: the predefined clause \samp{\#readIdentifier}, which does the same work,
   
IDENT ::= #!ignore ['a'..'z'|'A'..'Z'|'_']
   
                    ['a'..'z'|'A'..'Z'|'_'|'0'..'9']*;

Covered source code: 83%