declare function readType(myType : node); while skipEmptyCpp() { if !readIfEqualToIdentifier("class") error("'class' expected"); skipEmptyCpp(); local sClassName = readIdentifier(); if !sClassName error("class name expected"); //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; skipEmptyCpp(); if readIfEqualTo(":") { skipEmptyCpp(); local sParentName = readIdentifier(); if !sParentName error("parent name expected for class '" + sClassName + "'"); //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; skipEmptyCpp(); } if !readIfEqualTo("{") error("'{' expected"); skipEmptyCpp(); //note: to work easier with the current class node \samp{project.listOfClasses[sClassName]}, //note: we define a reference to it, called \samp{myClass}, local myClass; ref myClass = project.listOfClasses[sClassName]; while !readIfEqualTo("}") { skipEmptyCpp(); //note: the class is populated with the characteristics of the member once //note: its declaration has finished. Otherwise, it may confuse between an attribute //note: or a method declaration. So, we should have factorized the type declaration //note: and the name of the member into a common clause, for example. local myType; readType(myType); skipEmptyCpp(); local sMemberName = readIdentifier(); if !sMemberName error("attribute or method name expected"); skipEmptyCpp(); if readIfEqualTo("(") { //note: about parsing, methods are modeled into node //note: \textbf{myClass.listOfMethods[}\textit{sMemberName}\textbf{]}, insert myClass.listOfMethods[sMemberName].name = sMemberName; //note: attribute \samp{name} is compulsory into a \textit{type} node, so if //note: \samp{myType.name} returns \samp{"void"}, there is no return type, if myType.name != "void" { setall myClass.listOfMethods[sMemberName].type = myType; } skipEmptyCpp(); if !readIfEqualTo(")") { //note: to work easier with the current class node \samp{myClass.listOfMethods[sMemberName]}, //note: we define a reference to it, called \samp{myMethod}, local myMethod; ref myMethod = myClass.listOfMethods[sMemberName]; do { skipEmptyCpp(); local iPosition = getInputLocation(); local sMode = readIdentifier(); if !sMode error("parameter type or mode expected"); if (sMode != "in") && (sMode != "out") && (sMode != "inout") { setInputLocation(iPosition); set sMode = ""; } skipEmptyCpp(); local myParameterType; readType(myParameterType); skipEmptyCpp(); local sParameterName = readIdentifier(); if !sParameterName error("parameter name expected"); //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 = myParameterType; if sMode { insert myMethod.listOfParameters[sParameterName].name = sMode; } skipEmptyCpp(); } while readIfEqualTo(","); if !readIfEqualTo(")") error("')' expected"); } skipEmptyCpp(); } else { //note: about parsing, attributes are modeled into node //note: \textbf{myClass.listOfAttributes[}\textit{sMemberName}\textbf{]}, insert myClass.listOfAttributes[sMemberName].name = sMemberName; //note: the type is allocated on the stack, so it is copied into branch \samp{type} //note: (no node reference) integrally, setall myClass.listOfAttributes[sMemberName].type = myType; } if !readIfEqualTo(";") error("';' expected to close an attribute, instead of '" + readChar() + "'"); skipEmptyCpp(); } } //note: once the parsing of file has achieved, a message of success is written, traceLine("the file has been parsed successfully"); //note: function \samp{readType()} requires a node into which description of type //note: will be populated, function readType(myType : node) { local sType = readIdentifier(); if !sType error("type modifier or name expected, instead of '" + readChar() + "'"); if sType == "aggregate" { //note: about parsing, \textbf{myType.isAggregation} contains \samp{true} if type is an array, insert myType.isAggregation = true; skipEmptyCpp(); sType = readIdentifier(); if !sType error("aggregated class name expected"); } //note: about parsing, \textbf{myType.name} contains the name of basic type, insert myType.name = sType; //note: check whether the type is a basic one or a class specifier, if (sType != "int") && (sType != "double") && (sType != "boolean") && (sType != "string") { //note: about parsing, \textbf{myType.isObject} contains \samp{true} because //note: we suppose that this type is a class specifier (by default: it isn't a basic type), insert myType.isObject = true; } skipEmptyCpp(); if readIfEqualTo("[") { skipEmptyCpp(); if !readIfEqualTo("]") error("']' expected to close an array declaration"); //note: about parsing, \textbf{myType.isArray} contains \samp{true} if type is an array, insert myType.isArray = true; } }