//************************************************************************** // Translate the HTML documentation of the C++ API // // // This script generates an HTML file for CodeWorker while the parsing of // the corresponding file coming from the C++ API. // // It illustrates how CodeWorker proceeds for program transformation // (translation where the source and the target languages are the same). //************************************************************************** // Return the class name and the function name (if any, it could be the // description of a class), deduced of the HTML file name. function getClassFunctionName(sClassName : node, sFunctionName : node) { sClassName = rsubString(getShortFilename(getInputFilename()), 4); sFunctionName = sClassName.subString($sClassName.findString('.') + 1$); sClassName = sClassName.rsubString($sFunctionName.length() + 1$); } // The header BNF production rule of the grammar (entry point of the grammar). // As the transformation is very straight-forward and because of lazyness, the // whole transformation is written into this unique rule. HTMLdoc ::= // ignore whitespaces and carriage returns between BNF terminals and // non-terminals #ignore(blanks) // means that the rest of the sequence MUST NOT fail; if so, a detailed // error message interrupts the parsing #continue // what you read if what you generate: // the input file is automatically copied to the output file, while parsing #implicitCopy // jump directly to the version number of Chart Director ->"

ChartDirector Ver" // be sure the version number has the expected format #readInteger ['.' #continue #readInteger]* [ // desactivate the implicit copy: // we don't copy anymore what is read to the output file #explicitCopy "(C++ Edition)" // write '(CodeWorker Edition)' to the output file, in place of // '(C++ Edition)' => {@(CodeWorker Edition)@} ] "

" // at least one template must be recognized, but we could find more. // Each template gives rise to a specific translation. [ // jump to one of the following template alternatives ->[ // First template: it detects an embedded C++ example "[The following code is available in \"" #continue // must be valid up to the end of the sequence // don't copy the input file to the output file automatically // anymore #explicitCopy "cppdemo/" // the local variable 'sExample' contains the name of the C++ example #readIdentifier:sExample // replace the example path by the one for CodeWorker => {@cwdemo/@sExample@".]@endl()@@} // the following terminal is read, but certainly not copied! // (implicit copy still desactivated) "\". A MFC version of the code is available in \"mfcdemo\" (Windows edition only).]" [ // what you read is what you write, just for this block #implicitCopy "
"
				]
				// load the CodeWorker script and convert the special characters for HTML.
				// Close it with the tag '
' that will be ignored 2 lines below => {@@composeHTMLLikeString(loadFile(getWorkingPath() + "cwdemo/" + sExample + '/' + sExample + ".cws"))@@} // ignore the C++ example upto the tag '' included ->"" // what you read is what you write #implicitCopy "
" | // Second template: it detects a C++ function prototype "

Usage

" #continue "
" #skipIgnore // force the reading of blanks // from here, the implicit copy is desactivated #explicitCopy // How many parameters does this prototype exposes? // We need this information further, to determine the // corresponding CodeWorker prototype => local iParamSize = 0; // The '|>' is special: the left-hand side BNF expression // covers an area in the input file and the right-hand // side parses it, restricted to the covered area. // Here, the rhs jumps from parameters to parameters, // looking for ',' and ')', not limited to the end of // the input file, but to the first "
" encountered // (excluded). [ [~""]* |> [ // jump to the beginning of the parameters // declaration ->'(' [ // at least one parameter !')' => increment(iParamSize); // iterate on commas [ // count another parameter for each comma // encountered ',' => increment(iParamSize); | // continue the loop, looking for commas, // except if the trailing parenthesis // was reached ~')' ]* ]? // consume the trailing parenthesis ')' ] ] => { // extract the class name and the method name // or // the 'Chart' namespace and the function name local sClassName, sFunctionName; getClassFunctionName(sClassName, sFunctionName); local theClass; // searching for the class in the parse tree if !this.classes.findElement(sClassName) { // The class wasn't found. if sClassName in {"CChartViewer", "DoubleArray", "IntArray", "MemBlock", "StringArray"} { // Perhaps is it an utility class? In that case, we don't care because CodeWorker // manages them differently. @The class @sClassName@ doesn't exist in the CodeWorker's plugin. Please ignore this file. @ } else if sClassName == "Chart" { // no, but perhaps is it the namespace 'Chart'? // Yes, so we point to the namespace declaration // (don't care if it isn't a class: the parse tree of // the namespace is the same as for a class) ref theClass = this.namespaces["Chart"]; } else { // interrupt the parsing: it doesn't concern the C++ API error("class '" + sClassName + "' not found"); } } else { // It is a class, so we point to its declaration ref theClass = this.classes[sClassName]; } if !theClass.functions.empty() { // look for the function in the class. if theClass.functions[sFunctionName].empty() { if theClass.functions[sFunctionName.rsubString(1)].empty() { // if no prototype found, even without the trailing digit if any, // for the function name, write a warning both in the console // and in the output file. // Note: the trailing digit is found on HTML function names, // which have more than one occurrence in a class local sMessage = "method '" + sClassName + "::" + sFunctionName + "' not found in the C++ API!"; traceLine("warning: " + sMessage); @@sMessage@ @ } else { // it works without the last character: we assume that it is a // trailing digit, so we remove it from the name of the function sFunctionName = sFunctionName.rsubString(1); } } } // we iterate all prototypes of the function, which have been binded into the // plugin (is_packaged) and which have the expected number of parameters. // Then, for each of them, we generate the prototype foreach i in theClass.functions[sFunctionName] if i.is_packaged && $i.parameters.size() == iParamSize$ { @CHART::@sFunctionName@@ if sClassName != "Chart" { @@i.parameters.size()@(instance : node@ } else { @(@ } foreach j in i.parameters { if sClassName != "Chart" || !j.first() { @, @ } @@j.key()@ : @ if isNodeType(j.type) { @node@ } else { @value@ } } if i.output_param { @, returnValue : node@ } @); @ } } | // Third template: it detects the description of C++ arguments // of a function "

Arguments

" #continue "
" => local sClassName, sFunctionName; => local theClass; => { // extract the class name and the method name // or // the 'Chart' namespace and the function name getClassFunctionName(sClassName, sFunctionName); if this.classes.findElement(sClassName) { @The argument instance is an object of kind @sClassName@.

@ ref theClass = this.classes[sClassName]; if theClass.functions[sFunctionName].empty() && !theClass.functions[sFunctionName.rsubString(1)].empty() { sFunctionName = sFunctionName.rsubString(1); } } else if sClassName == "Chart" { ref theClass = this.namespaces[sClassName]; } } // Now, one have several alternatives [ // no function name: this HTML file is about a class, // not about a function. This template is ignored #check(!theClass.functions.findElement(sFunctionName)) | // this function has no arguments #explicitCopy "None" #continue #implicitCopy "
" | // this function has its arguments explained in a table #continue "" "" "" // add a column into the table, indicating the type of the parameter => {@@} "" "" // count the number of lines into the table, to determine how many // parameters the function has. // Note: the BNF operator '!!' means to look ahead without moving the // input file cursor => local iParamSize = 0; !!["" ->"" => increment(iParamSize);]+ // retrieve the parameter types of the first function prototype, whose // parameter size is the one expected => local params; => { foreach i in theClass.functions[sFunctionName] if i.is_packaged { if $i.parameters.size() == iParamSize$ { ref params = i.parameters; break; } } } => local iParam = 0; // an index for iterating the 'params' array [ "" #continue // don't touch the first column of the table (name of the argument) "" => if $params.size() == iParamSize$ { // we have found a prototype of this function: // we populate the column added for the type @@ } else { // manifestly, we didn't find a prototype: no type @@ } "" "" "" => increment(iParam); ]+ ] | // Fourth template: it detects the description of all C++ methods // belonging to a class "" #continue "" [ // while reading the first column (name of the method), we extract the // class name and the method name from the HTML link. If they don't // exist in the parse tree, we don't change the presentation. #explicitCopy "" "" | "" #continue [ // description of an existing method: we have to change the presentation "" "" "" | // this row contains only one column, certainly grey, showing a note: // nothing to change ->"" ] ]+ | // Fifth template: it detects a table showing all constants with their description. // Nothing to do. "
ArgumentTypeDefaultDescription
" ->"@getHTMLType(params#[iParam].type)@ " [ // check that we have found a prototype #check($params.size() == iParamSize$) // if the default value of the argument is a HTML link, // and if the type is an enum, we change the presentation: // an enum is seen as a constant string in the CodeWorker binding // of Chart Director (it's a choice!). " {@"@} [~""]* => {@"@} ]? ]? ->"" ->"
MethodInheritedDescription
" ""
" #continue " sFunctionName = sFunctionName.rsubString(1); ]? ->'>' // here is the change => {@CHART::@sFunctionName@@} [ #explicitCopy [~""]* ] ->"" "" ->"" ->"
" #continue "" | "" | ""]]* [""]? ]+ | // Sixth template: it detects some example titles with their description. // Nothing to do. "
ConstantValueDescription" #continue [ "
" => {@"@} [~[""]]* => {@"@} [~["
" "" "" "" | // Seventh template: it detects the C++ declaration of a constant value. // Translates it for CodeWorker. "

" [ #explicitCopy "Declaration" => {@Usage@} ] "

" #continue "
" #explicitCopy => { local sClassName, sFunctionName; getClassFunctionName(sClassName, sFunctionName); @A constant string that refers to the internal constant value, described below. The constant string is anyone among: @ } [~"
"]* ] ]+ // jump up to the end of the file, constraining to copy the rest of the input file // to the output file ->#empty ;
TitleDescription