1/* "CodeWorker": a scripting language for parsing and generating text. 2 3Copyright (C) 1996-1997, 1999-2002 C�dric Lemaire 4 5This library is free software; you can redistribute it and/or 6modify it under the terms of the GNU Lesser General Public 7License as published by the Free Software Foundation; either 8version 2.1 of the License, or (at your option) any later version. 9 10This library is distributed in the hope that it will be useful, 11but WITHOUT ANY WARRANTY; without even the implied warranty of 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13Lesser General Public License for more details. 14 15You should have received a copy of the GNU Lesser General Public 16License along with this library; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 19To contact the author: codeworker@free.fr 20*/ 21 22function checkType(sType : value) { 23 switch(sType) { 24 case "int": 25 case "bool": 26 case "double": 27 case "doubleref": 28 case "boolref": 29 case "iterator": 30 case "script": 31 case "string": 32 case "stringref": 33 case "stringlist": 34 case "treeref": 35 case "tree": 36 case "treexpr": 37 case "ulong": 38 case "ushort": 39 return "true"; 40 default: 41 return ""; 42 } 43} 44 45function parseType(myType : node) { 46 local sType = readIdentifier(); 47 if !sType error("syntax error: type expected, instead of '" + readChar() + "'"); 48 if !sType.checkType() error("unrecognized type '" + sType + "' found"); 49 if sType == "script" { 50 skipEmptyCpp(); 51 if !readIfEqualTo('<') error("'<' expected after 'script' type"); 52 skipEmptyCpp(); 53 set sType = readIdentifier(); 54 switch(sType) { 55 case "BNF": 56 case "free": 57 case "pattern": 58 case "translate": 59 insert myType.script = sType; 60 break; 61 default: 62 error("'script<" + sType + ">' doesn't exist as a type"); 63 } 64 skipEmptyCpp(); 65 if !readIfEqualTo('>') error("'>' expected to close 'script' type"); 66 set myType = "script"; 67 } else { 68 set myType = sType; 69 } 70} 71 72function parseMemberDocumentation(myMember : node, sMemberName, sMemberType) { 73 nop(skipEmptyCpp()); 74 if !readIfEqualTo("=") error("syntax error: '=' expected to provide documentation of " + sMemberType + " '" + sMemberName + "'"); 75 nop(skipEmptyCpp()); 76 local sDocumentation; 77 if !readString(sDocumentation) error("syntax error: documentation of " + sMemberType + " '" + sMemberName + "' expected between quotes"); 78 local sText; 79 while skipEmptyCpp() && readString(sText) set sDocumentation += endl() + sText; 80 insert myMember.documentation = sDocumentation; 81 nop(skipEmptyCpp()); 82 if !readIfEqualToIdentifier("heading") error("'heading' keyword required after the definition of '" + sMemberName + "'"); 83 nop(skipEmptyCpp()); 84 local sIdentifier; 85 if readString(sIdentifier) insert myMember.abstract = sIdentifier; 86 do { 87 nop(skipEmptyCpp()); 88 set sIdentifier = readIdentifier(); 89 if !sIdentifier error("heading name expected"); 90 switch(sIdentifier) { 91 case "array": 92 case "command": 93 case "conversion": 94 case "datetime": 95 case "directory": 96 case "file": 97 case "generation": 98 case "iterator": 99 case "interpreter": 100 case "node": 101 case "numeric": 102 case "parsing": 103 case "socket": 104 case "standard": 105 case "string": 106 case "system": 107 case "unknown": 108 case "URL": 109 insert myMember.headings[sIdentifier] = sIdentifier; 110 ref project.headings[sIdentifier].members[sMemberName] = myMember; 111 insert project.headings[sIdentifier].modes[myMember.mode]; 112 } 113 nop(skipEmptyCpp()); 114 } while readIfEqualTo(','); 115 if readIfEqualToIdentifier("input") { 116 nop(skipEmptyCpp()); 117 local sInput; 118 if !readString(sInput) error("syntax error: input of " + sMemberType + " '" + sMemberName + "' expected between quotes"); 119 while skipEmptyCpp() && readString(sText) set sInput += endl() + sText; 120 insert myMember.input = sInput; 121 nop(skipEmptyCpp()); 122 } 123 if readIfEqualToIdentifier("example") { 124 nop(skipEmptyCpp()); 125 if readIfEqualToIdentifier("new_project") { 126 insert myMember.example.newProject = true; 127 nop(skipEmptyCpp()); 128 } 129 if readIfEqualToIdentifier("expand") { 130 insert myMember.example.expand = true; 131 nop(skipEmptyCpp()); 132 } 133 if readIfEqualToIdentifier("standard_input") { 134 nop(skipEmptyCpp()); 135 if !readIfEqualTo("(") error("'(' expected after 'standard_input'"); 136 nop(skipEmptyCpp()); 137 if !readString(myMember.example.standardInput) error("'standard_input' expects the keyboard input"); 138 nop(skipEmptyCpp()); 139 if !readIfEqualTo(")") error("')' expected after 'standard_input'"); 140 nop(skipEmptyCpp()); 141 } 142 local sExample; 143 if !readString(sExample) error("syntax error: example of " + sMemberType + " '" + sMemberName + "' expected between quotes"); 144 while skipEmptyCpp() && readString(sText) set sExample += endl() + sText; 145 insert myMember.example = sExample; 146 nop(skipEmptyCpp()); 147 } 148 if readIfEqualToIdentifier("deprecated") { 149 nop(skipEmptyCpp()); 150 local sKeyword = readIdentifier(); 151 if !sKeyword error("keyword expected for 'deprecated' on " + sMemberType + " '" + sMemberName + "'"); 152 nop(skipEmptyCpp()); 153 local sVersion; 154 if !readString(sVersion) error("version as a constant string expected for 'deprecated' on " + sMemberType + " '" + sMemberName + "'"); 155 insert myMember.deprecated.name = sKeyword; 156 insert myMember.deprecated.version = sVersion; 157 nop(skipEmptyCpp()); 158 } 159 if readIfEqualToIdentifier("bugs") { 160 nop(skipEmptyCpp()); 161 local sBugs; 162 if !readString(sBugs) error("syntax error: known bugs of " + sMemberType + " '" + sMemberName + "' expected between quotes"); 163 while skipEmptyCpp() && readString(sText) set sBugs += endl() + sText; 164 insert myMember.bugs = sBugs; 165 nop(skipEmptyCpp()); 166 } 167 if readIfEqualToIdentifier("see") { 168 do { 169 nop(skipEmptyCpp()); 170 local sKeyword = readIdentifier(); 171 if !sKeyword error("keyword expected for 'see also' on " + sMemberType + " '" + sMemberName + "'"); 172 nop(skipEmptyCpp()); 173 insert myMember.seeAlso[sKeyword] = sKeyword; 174 } while readIfEqualTo(","); 175 nop(skipEmptyCpp()); 176 } 177} 178 179insert project.headings["interpreter"].description = "Function for running a \\CodeWorker\\ script"; 180insert project.headings["string"].description = "Functions for handling strings"; 181insert project.headings["array"].description = "Functions handling arrays"; 182insert project.headings["node"].description = "Functions handling a node"; 183insert project.headings["iterator"].description = "Functions handling an iterator"; 184insert project.headings["file"].description = "Functions handling files"; 185insert project.headings["directory"].description = "Functions handling directories"; 186insert project.headings["URL"].description = "Functions working on URL transfers (HTTP,...)"; 187insert project.headings["datetime"].description = "Functions handling date-time"; 188insert project.headings["numeric"].description = "Functions handling numbers"; 189insert project.headings["standard"].description = "Classical functions of any standard library"; 190insert project.headings["conversion"].description = "Type conversion"; 191insert project.headings["system"].description = "Functions relative to the operating system"; 192 193insert project.headings["command"].description = "Relative to the command line"; 194insert project.headings["generation"].description = "Functions relative to generation"; 195insert project.headings["parsing"].description = "Functions relative to scanning/parsing"; 196insert project.headings["socket"].description = "Socket operations"; 197insert project.headings["unknown"].description = "Various types of function"; 198 199while skipEmptyCpp() { 200 if readIfEqualTo("#") { 201 local sLine; 202 if !readLine(sLine) break; 203 continue; 204 } 205 local sIdentifier = readIdentifier(); 206 if !sIdentifier error("syntax error: 'procedure' or 'function' or 'method' keyword expected, instead of '" + readChar() + "'"); 207 if sIdentifier == "procedure" { 208 nop(skipEmptyCpp()); 209 local sMode; 210 if readIfEqualTo("[") { 211 nop(skipEmptyCpp()); 212 set sMode = readIdentifier(); 213 if !sMode error("syntax error: script mode expected, instead of '" + readChar() + "'"); 214 if (sMode != "generate") && (sMode != "parse") error("syntax error: 'generate' or 'parse' keyword expected, instead of identifier '" + sIdentifier + "'"); 215 nop(skipEmptyCpp()); 216 if !readIfEqualTo("]") error("syntax error: ']' expected after script mode '" + sMode + "'"); 217 nop(skipEmptyCpp()); 218 } 219 local sFunction = readIdentifier(); 220 if !sFunction error("syntax error: procedure name expected, instead of '" + readChar() + "'"); 221 insert project.procedureList[sFunction].name = sFunction; 222 if sMode insert project.procedureList[sFunction].mode = sMode; 223 nop(skipEmptyCpp()); 224 if !readIfEqualTo("(") error("syntax error: '(' expected after 'procedure " + sFunction + "'"); 225 nop(skipEmptyCpp()); 226 if !readIfEqualTo(")") { 227 local bHasDefault; 228 do { 229 nop(skipEmptyCpp()); 230 local sParameter = readIdentifier(); 231 insert project.procedureList[sFunction].parameterList[sParameter].name = sParameter; 232 nop(skipEmptyCpp()); 233 if !readIfEqualTo(":") error("syntax error: ':' expected to declare type of parameter " + sParameter + "'"); 234 nop(skipEmptyCpp()); 235 parseType(project.procedureList[sFunction].parameterList[sParameter].type); 236 nop(skipEmptyCpp()); 237 local sDefaultValue; 238 if readIfEqualTo(":") { 239 nop(skipEmptyCpp()); 240 sDefaultValue = readIdentifier(); 241 if sDefaultValue { 242 if sDefaultValue == "true" sDefaultValue = "\"true\""; 243 else if sDefaultValue == "false" sDefaultValue = "\"\""; 244 else if !(sDefaultValue in {"project", "this", "null"}) { 245 error("unknown constant variable '" + sDefaultValue + "'"); 246 } 247 } else { 248 if readString(sDefaultValue) sDefaultValue = '"' + sDefaultValue.composeCLikeString() + '"'; 249 else if !readNumber(sDefaultValue) { 250 error("default value expected"); 251 } 252 } 253 insert project.procedureList[sFunction].parameterList[sParameter].default = sDefaultValue; 254 nop(skipEmptyCpp()); 255 bHasDefault = true; 256 } else if bHasDefault { 257 error("default value expected after argument " + sParameter); 258 } 259 nop(skipEmptyCpp()); 260 if !readIfEqualTo("=") error("syntax error: '=' expected to provide documentation of parameter '" + sParameter + "'"); 261 nop(skipEmptyCpp()); 262 local sDocumentation; 263 if !readString(sDocumentation) error("syntax error: documentation of parameter '" + sParameter + "' expected between quotes"); 264 insert project.procedureList[sFunction].parameterList[sParameter].documentation = sDocumentation; 265 nop(skipEmptyCpp()); 266 } while readIfEqualTo(","); 267 if !readIfEqualTo(")") error("syntax error: ')' expected to close parameter declaration of procedure '" + sFunction + "'"); 268 } 269 nop(skipEmptyCpp()); 270 if readIfEqualTo("[") { 271 nop(skipEmptyCpp()); 272 local sModifier = readIdentifier(); 273 if !sModifier error("syntax error: modifier expected for procedure '" + sFunction + "'"); 274 if (sModifier != "user") && (sModifier != "info") && (sModifier != "visibility") error("syntax error: unrecognized modifier '" + sModifier + "' found for procedure '" + sFunction + "'"); 275 insert project.procedureList[sFunction].modifierList[sModifier] = sModifier; 276 nop(skipEmptyCpp()); 277 if !readIfEqualTo("]") error("syntax error: ']' expected at the end of modifier '" + sModifier + "'"); 278 nop(skipEmptyCpp()); 279 } 280 parseMemberDocumentation(project.procedureList[sFunction], sFunction, "procedure"); 281 if !readIfEqualTo(";") error("syntax error: ';' expected at the end of procedure '" + sFunction + "'"); 282 } else if sIdentifier == "function" { 283 nop(skipEmptyCpp()); 284 local sMode; 285 if readIfEqualTo("[") { 286 nop(skipEmptyCpp()); 287 set sMode = readIdentifier(); 288 if !sMode error("syntax error: script mode expected, instead of '" + readChar() + "'"); 289 if (sMode != "generate") && (sMode != "parse") error("syntax error: 'generate' or 'parse' keyword expected, instead of identifier '" + sIdentifier + "'"); 290 nop(skipEmptyCpp()); 291 if !readIfEqualTo("]") error("syntax error: ']' expected after script mode '" + sMode + "'"); 292 nop(skipEmptyCpp()); 293 } 294 local sFunction = readIdentifier(); 295 if !sFunction error("syntax error: function name expected, instead of '" + readChar() + "'"); 296 insert project.functionList[sFunction].name = sFunction; 297 if sMode insert project.functionList[sFunction].mode = sMode; 298 nop(skipEmptyCpp()); 299 if !readIfEqualTo("(") error("syntax error: '(' expected after 'function " + sFunction + "'"); 300 nop(skipEmptyCpp()); 301 if !readIfEqualTo(")") { 302 local bHasDefault; 303 do { 304 nop(skipEmptyCpp()); 305 local sParameter = readIdentifier(); 306 insert project.functionList[sFunction].parameterList[sParameter].name = sParameter; 307 nop(skipEmptyCpp()); 308 if !readIfEqualTo(":") error("syntax error: ':' expected to declare type of parameter " + sParameter + "'"); 309 nop(skipEmptyCpp()); 310 parseType(project.functionList[sFunction].parameterList[sParameter].type); 311 nop(skipEmptyCpp()); 312 local sDefaultValue; 313 if readIfEqualTo(":") { 314 nop(skipEmptyCpp()); 315 sDefaultValue = readIdentifier(); 316 if sDefaultValue { 317 if sDefaultValue == "true" sDefaultValue = "\"true\""; 318 else if sDefaultValue == "false" sDefaultValue = "\"\""; 319 else if !(sDefaultValue in {"project", "this", "null"}) { 320 error("unknown constant variable '" + sDefaultValue + "'"); 321 } 322 } else { 323 if !readNumber(sDefaultValue) { 324 if !readString(sDefaultValue) error("default value expected"); 325 sDefaultValue = '"' + sDefaultValue.composeCLikeString() + '"'; 326 } 327 } 328 insert project.functionList[sFunction].parameterList[sParameter].default = sDefaultValue; 329 nop(skipEmptyCpp()); 330 bHasDefault = true; 331 } else if bHasDefault { 332 error("default value expected after argument " + sParameter); 333 } 334 nop(skipEmptyCpp()); 335 if !readIfEqualTo("=") error("syntax error: '=' expected to provide documentation of parameter '" + sParameter + "'"); 336 nop(skipEmptyCpp()); 337 local sDocumentation; 338 if !readString(sDocumentation) error("syntax error: documentation of parameter '" + sParameter + "' expected between quotes"); 339 insert project.functionList[sFunction].parameterList[sParameter].documentation = sDocumentation; 340 nop(skipEmptyCpp()); 341 } while readIfEqualTo(","); 342 if !readIfEqualTo(")") error("syntax error: ')' expected to close parameter declaration of function '" + sFunction + "'"); 343 } 344 nop(skipEmptyCpp()); 345 if !readIfEqualTo(":") error("syntax error: ':' expected before declaring return type of function '" + sFunction + "'"); 346 nop(skipEmptyCpp()); 347 parseType(project.functionList[sFunction].return_type); 348 nop(skipEmptyCpp()); 349 if readIfEqualTo("[") { 350 nop(skipEmptyCpp()); 351 local sModifier = readIdentifier(); 352 if !sModifier error("syntax error: modifier expected for function '" + sFunction + "'"); 353 if (sModifier != "user") && (sModifier != "info") error("syntax error: unrecognized modifier '" + sModifier + "' found for function '" + sFunction + "'"); 354 insert project.functionList[sFunction].modifierList[sModifier] = sModifier; 355 nop(skipEmptyCpp()); 356 if !readIfEqualTo("]") error("syntax error: ']' expected at the end of modifier '" + sModifier + "'"); 357 nop(skipEmptyCpp()); 358 } 359 parseMemberDocumentation(project.functionList[sFunction], sFunction, "function"); 360 if !readIfEqualTo(";") error("syntax error: ';' expected at the end of function '" + sFunction + "'"); 361 } else if sIdentifier == "method" { 362 nop(skipEmptyCpp()); 363 local sMethod = readIdentifier(); 364 if !sMethod error("syntax error: method identifier expected after keyword 'method'"); 365 nop(skipEmptyCpp()); 366 if !readIfEqualToIdentifier("is") error("syntax error: 'is' expected after the declaration of method '" + sMethod +"'"); 367 nop(skipEmptyCpp()); 368 local sFunction = readIdentifier(); 369 if !sFunction error("syntax error: function identifier expected after declaration of method '" + sMethod + "'"); 370 nop(skipEmptyCpp()); 371 if !findElement(sFunction, project.functionList) error("unknown function '" + sFunction + "' while declaring method '" + sMethod + "'"); 372 insert project.methodList[sMethod].function = sFunction; 373 if readIfEqualTo("(") { 374 nop(skipEmptyCpp()); 375 local sThis = readIdentifier(); 376 if !sThis error("syntax error: 'this' parameter expected after declaration of method '" + sMethod + "'"); 377 if !findElement(sThis, project.functionList[sFunction].parameterList) error("syntax error: '" + sThis + "' isn't a parameter on function '" + sFunction + "', while declaring method '" + sMethod + "'"); 378 insert project.methodList[sMethod].thisParameter = sThis; 379 nop(skipEmptyCpp()); 380 if !readIfEqualTo(")") error("syntax error: ')' expected after giving the 'this' parameter of method '" + sMethod + "'"); 381 nop(skipEmptyCpp()); 382 } 383 if !readIfEqualTo(";") error("syntax error: ';' expected at the end of method '" + sMethod + "'"); 384 insert project.functionList[sFunction].method = sMethod; 385 } else { 386 error("syntax error: 'procedure' or 'function' or 'method' keyword expected, instead of identifier '" + sIdentifier + "'"); 387 } 388} 389 390foreach i in project.functionList { 391 foreach j in i.seeAlso { 392 local myMember; 393 if findElement(j, project.functionList) { 394 ref myMember = project.functionList[j]; 395 } else if findElement(j, project.procedureList) { 396 ref myMember = project.procedureList[j]; 397 } else { 398 error("function '" + i.name + "' asks for seeing also function/procedure '" + j + "' that doesn't exist"); 399 } 400 insert myMember.seeAlso[i.name] = i.name; 401 foreach k in i.seeAlso if k != j insert myMember.seeAlso[k] = k; 402 } 403} 404foreach i in project.procedureList { 405 foreach j in i.seeAlso { 406 local myMember; 407 if findElement(j, project.functionList) { 408 ref myMember = project.functionList[j]; 409 } else if findElement(j, project.procedureList) { 410 ref myMember = project.procedureList[j]; 411 } else { 412 error("procedure '" + i.name + "' asks for seeing also function/procedure '" + j + "' that doesn't exist"); 413 } 414 insert myMember.seeAlso[i.name] = i.name; 415 foreach k in i.seeAlso if k != j insert myMember.seeAlso[k] = k; 416 } 417} 418