1 /* 2 * Copyright (c) 2014 Nonki Takahashi. All rights reserved. 3 * 4 * History: 5 * 0.2 2014-01-17 Created by EBNFParser. Runner has been separated. 6 */ 7 8 /** 9 * @fileOverview EBNFParser - EBNF Parser Object 10 * @version 0.2 11 * @author EBNFParser written by Nonki Takahashi 12 */ 13 14 /** 15 * EBNF Parser Generator Object 16 * @this {EBNFParser} 17 * @param {String} syntax syntax object for generate parser 18 * @param {Object} gapFree array of gap free id 19 * @param {String} name name of the parser 20 * @param {String} ver version of the parser 21 * @param {Boolean} ignoreCase true if ignore case (optional) 22 * @property {String} buf syntax buffer 23 * @property {Integer} ptr syntax buffer pointer 24 * @property {Object} gapFree array of gap free id 25 * @property {String} name name of the parser 26 * @property {String} ver version of the parser 27 * @property {Boolean} ignoreCase true if ignore case 28 * @since 0.2 29 */ 30 EBNFParser = function(syntax, gapFree, name, ver, ignoreCase) { 31 this.gapFree = gapFree; 32 this.name = name; 33 this.ver = ver; 34 if (ignoreCase) 35 this.ignoreCase = true; 36 else 37 this.ignoreCase = false; 38 this.inGapFree = false; 39 // inherit the methods of class Lex 40 Lex.call(this, syntax); 41 }; 42 EBNFParser.prototype = new Lex(); 43 44 /** 45 * syntax = rule, {rule}. 46 * @returns {String} code generated if matched, null if not matched 47 * @since 0.2 48 */ 49 EBNFParser.prototype.syntax = function() { 50 var match = []; 51 var save = this.ptr; 52 var n = -1; 53 this.sp(); 54 match[++n] = this.rule(); 55 if (match[n]) { 56 this.sp(); 57 while (match[n]) { 58 this.sp(); 59 match[++n] = this.rule(); 60 } 61 match[++n] = true; 62 } 63 if (!match[n]) { 64 this.ptr = save; 65 return null; 66 } 67 return this.run(n, match, "syntax"); 68 }; 69 70 /** 71 * rule = idl, '=', alternative, '.'. 72 * @returns {String} code generated if matched, null if not matched 73 * @since 0.2 74 */ 75 EBNFParser.prototype.rule = function() { 76 var match = []; 77 var save = this.ptr; 78 var n = -1; 79 this.sp(); 80 match[++n] = this.idl(); 81 if (match[n]) { 82 this.sp(); 83 match[++n] = this.text('='); 84 } 85 if (match[n]) { 86 this.sp(); 87 match[++n] = this.alternative(); 88 } 89 if (match[n]) { 90 this.sp(); 91 match[++n] = this.text('.'); 92 } 93 if (!match[n]) { 94 this.ptr = save; 95 return null; 96 } 97 return this.run(n, match, "rule"); 98 }; 99 100 /** 101 * alternative = sequence, {'|', sequence}. 102 * @returns {String} code generated if matched, null if not matched 103 * @since 0.2 104 */ 105 EBNFParser.prototype.alternative = function() { 106 var match = []; 107 var save = this.ptr; 108 var n = -1; 109 this.sp(); 110 match[++n] = this.sequence(); 111 if (match[n]) { 112 this.sp(); 113 while (match[n]) { 114 this.sp(); 115 match[++n] = this.text('|'); 116 if (match[n]) { 117 this.sp(); 118 match[++n] = this.sequence(); 119 } 120 } 121 match[++n] = true; 122 } 123 if (!match[n]) { 124 this.ptr = save; 125 return null; 126 } 127 return this.run(n, match, "alternative"); 128 }; 129 130 /** 131 * sequence = term, {',', term}. 132 * @returns {String} code generated if matched, null if not matched 133 * @since 0.2 134 */ 135 EBNFParser.prototype.sequence = function() { 136 var match = []; 137 var save = this.ptr; 138 var n = -1; 139 this.sp(); 140 match[++n] = this.term(); 141 if (match[n]) { 142 this.sp(); 143 while (match[n]) { 144 this.sp(); 145 match[++n] = this.text(','); 146 if (match[n]) { 147 this.sp(); 148 match[++n] = this.term(); 149 } 150 } 151 match[++n] = true; 152 } 153 if (!match[n]) { 154 this.ptr = save; 155 return null; 156 } 157 return this.run(n, match, "sequence"); 158 }; 159 160 /** 161 * term = primary. 162 * @returns {String} code generated if matched, null if not matched 163 * @since 0.2 164 */ 165 EBNFParser.prototype.term = function() { 166 var match = []; 167 var save = this.ptr; 168 var n = -1; 169 this.sp(); 170 match[++n] = this.primary(); 171 if (!match[n]) { 172 this.ptr = save; 173 return null; 174 } 175 return this.run(n, match, "term"); 176 }; 177 178 /** 179 * primary = terminal | id | repeat | option | group. 180 * @returns {String} code generated if matched, null if not matched 181 * @since 0.2 182 */ 183 EBNFParser.prototype.primary = function() { 184 var match = []; 185 var save = this.ptr; 186 var n = -1; 187 this.sp(); 188 match[++n] = this.terminal(); 189 if (!match[n]) { 190 n--; 191 this.sp(); 192 match[++n] = this.id(); 193 } 194 if (!match[n]) { 195 n--; 196 this.sp(); 197 match[++n] = this.repeat(); 198 } 199 if (!match[n]) { 200 n--; 201 this.sp(); 202 match[++n] = this.option(); 203 } 204 if (!match[n]) { 205 n--; 206 this.sp(); 207 match[++n] = this.group(); 208 } 209 if (!match[n]) { 210 this.ptr = save; 211 return null; 212 } 213 return this.run(n, match, "primary"); 214 }; 215 216 /** 217 * terminal = sq, character, {character}, sq. 218 * @returns {String} code generated if matched, null if not matched 219 * @since 0.2 220 */ 221 EBNFParser.prototype.terminal = function() { 222 var match = []; 223 var save = this.ptr; 224 var n = -1; 225 this.sp(); 226 match[++n] = this.sq(); 227 if (match[n]) { 228 match[++n] = this.character(); 229 } 230 if (match[n]) { 231 while (match[n]) { 232 match[++n] = this.character(); 233 } 234 match[++n] = true; 235 } 236 if (match[n]) { 237 match[++n] = this.sq(); 238 } 239 if (!match[n]) { 240 this.ptr = save; 241 return null; 242 } 243 return this.run(n, match, "terminal"); 244 }; 245 246 /** 247 * idl = letter, {letter | digit}. 248 * @returns {String} code generated if matched, null if not matched 249 * @since 0.2 250 */ 251 EBNFParser.prototype.idl = function() { 252 var match = []; 253 var save = this.ptr; 254 var n = -1; 255 this.sp(); 256 match[++n] = this.letter(); 257 if (match[n]) { 258 while (match[n]) { 259 match[++n] = this.letter(); 260 if (!match[n]) { 261 n--; 262 match[++n] = this.digit(); 263 } 264 } 265 match[++n] = true; 266 } 267 if (!match[n]) { 268 this.ptr = save; 269 return null; 270 } 271 return this.run(n, match, "idl"); 272 }; 273 274 /** 275 * id = letter, {letter | digit}. 276 * @returns {String} code generated if matched, null if not matched 277 * @since 0.2 278 */ 279 EBNFParser.prototype.id = function() { 280 var match = []; 281 var save = this.ptr; 282 var n = -1; 283 this.sp(); 284 match[++n] = this.letter(); 285 if (match[n]) { 286 while (match[n]) { 287 match[++n] = this.letter(); 288 if (!match[n]) { 289 n--; 290 match[++n] = this.digit(); 291 } 292 } 293 match[++n] = true; 294 } 295 if (!match[n]) { 296 this.ptr = save; 297 return null; 298 } 299 return this.run(n, match, "id"); 300 }; 301 302 /** 303 * option = '[', alternative, ']'. 304 * @returns {String} code generated if matched, null if not matched 305 * @since 0.2 306 */ 307 EBNFParser.prototype.option = function() { 308 var match = []; 309 var save = this.ptr; 310 var n = -1; 311 this.sp(); 312 match[++n] = this.text('['); 313 if (match[n]) { 314 this.sp(); 315 match[++n] = this.alternative(); 316 } 317 if (match[n]) { 318 this.sp(); 319 match[++n] = this.text(']'); 320 } 321 if (!match[n]) { 322 this.ptr = save; 323 return null; 324 } 325 return this.run(n, match, "option"); 326 }; 327 328 /** 329 * repeat = '{', alternative, '}'. 330 * @returns {String} code generated if matched, null if not matched 331 * @since 0.2 332 */ 333 EBNFParser.prototype.repeat = function() { 334 var match = []; 335 var save = this.ptr; 336 var n = -1; 337 this.sp(); 338 match[++n] = this.text('{'); 339 if (match[n]) { 340 this.sp(); 341 match[++n] = this.alternative(); 342 } 343 if (match[n]) { 344 this.sp(); 345 match[++n] = this.text('}'); 346 } 347 if (!match[n]) { 348 this.ptr = save; 349 return null; 350 } 351 return this.run(n, match, "repeat"); 352 }; 353 354 /** 355 * group = '(', alternative, ')'. 356 * @returns {String} code generated if matched, null if not matched 357 * @since 0.2 358 */ 359 EBNFParser.prototype.group = function() { 360 var match = []; 361 var save = this.ptr; 362 var n = -1; 363 this.sp(); 364 match[++n] = this.text('('); 365 if (match[n]) { 366 this.sp(); 367 match[++n] = this.alternative(); 368 } 369 if (match[n]) { 370 this.sp(); 371 match[++n] = this.text(')'); 372 } 373 if (!match[n]) { 374 this.ptr = save; 375 return null; 376 } 377 return this.run(n, match, "group"); 378 }; 379 380 /** 381 * letter = lower | upper. 382 * @returns {String} code generated if matched, null if not matched 383 * @since 0.2 384 */ 385 EBNFParser.prototype.letter = function() { 386 var match = []; 387 var save = this.ptr; 388 var n = -1; 389 this.sp(); 390 match[++n] = this.lower(); 391 if (!match[n]) { 392 n--; 393 this.sp(); 394 match[++n] = this.upper(); 395 } 396 if (!match[n]) { 397 this.ptr = save; 398 return null; 399 } 400 return this.run(n, match, "letter"); 401 }; 402 403 /** 404 * character = symbol | letter | digit. 405 * @returns {String} code generated if matched, null if not matched 406 * @since 0.2 407 */ 408 EBNFParser.prototype.character = function() { 409 var match = []; 410 var save = this.ptr; 411 var n = -1; 412 this.sp(); 413 match[++n] = this.symbol(); 414 if (!match[n]) { 415 n--; 416 this.sp(); 417 match[++n] = this.letter(); 418 } 419 if (!match[n]) { 420 n--; 421 this.sp(); 422 match[++n] = this.digit(); 423 } 424 if (!match[n]) { 425 this.ptr = save; 426 return null; 427 } 428 return this.run(n, match, "character"); 429 }; 430 431 /** 432 * symbol = '=' | ',' | '.' | '|' | 433 '[' | ']' | '{' | '}' | '(' | ')'. 434 * @returns {String} code generated if matched, null if not matched 435 * @since 0.2 436 */ 437 EBNFParser.prototype.symbol = function() { 438 var match = []; 439 var save = this.ptr; 440 var n = -1; 441 this.sp(); 442 match[++n] = this.text('='); 443 if (!match[n]) { 444 n--; 445 this.sp(); 446 match[++n] = this.text(','); 447 } 448 if (!match[n]) { 449 n--; 450 this.sp(); 451 match[++n] = this.text('.'); 452 } 453 if (!match[n]) { 454 n--; 455 this.sp(); 456 match[++n] = this.text('|'); 457 } 458 if (!match[n]) { 459 n--; 460 this.sp(); 461 match[++n] = this.text('['); 462 } 463 if (!match[n]) { 464 n--; 465 this.sp(); 466 match[++n] = this.text(']'); 467 } 468 if (!match[n]) { 469 n--; 470 this.sp(); 471 match[++n] = this.text('{'); 472 } 473 if (!match[n]) { 474 n--; 475 this.sp(); 476 match[++n] = this.text('}'); 477 } 478 if (!match[n]) { 479 n--; 480 this.sp(); 481 match[++n] = this.text('('); 482 } 483 if (!match[n]) { 484 n--; 485 this.sp(); 486 match[++n] = this.text(')'); 487 } 488 if (!match[n]) { 489 this.ptr = save; 490 return null; 491 } 492 return this.run(n, match, "symbol"); 493 }; 494