|
|
@ -59,8 +59,6 @@ var Parser = (function ParserClosure() { |
|
|
|
if (isCmd(this.buf2, 'ID')) { |
|
|
|
if (isCmd(this.buf2, 'ID')) { |
|
|
|
this.buf1 = this.buf2; |
|
|
|
this.buf1 = this.buf2; |
|
|
|
this.buf2 = null; |
|
|
|
this.buf2 = null; |
|
|
|
// skip byte after ID
|
|
|
|
|
|
|
|
this.lexer.skip(); |
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
this.buf1 = this.buf2; |
|
|
|
this.buf1 = this.buf2; |
|
|
|
this.buf2 = this.lexer.getObj(); |
|
|
|
this.buf2 = this.lexer.getObj(); |
|
|
@ -155,9 +153,8 @@ var Parser = (function ParserClosure() { |
|
|
|
|
|
|
|
|
|
|
|
// searching for the /EI\s/
|
|
|
|
// searching for the /EI\s/
|
|
|
|
var state = 0, ch, i, ii; |
|
|
|
var state = 0, ch, i, ii; |
|
|
|
while (state != 4 && |
|
|
|
while (state != 4 && (ch = stream.getByte()) !== -1) { |
|
|
|
(ch = stream.getByte()) !== null && ch !== undefined) { |
|
|
|
switch (ch | 0) { |
|
|
|
switch (ch) { |
|
|
|
|
|
|
|
case 0x20: |
|
|
|
case 0x20: |
|
|
|
case 0x0D: |
|
|
|
case 0x0D: |
|
|
|
case 0x0A: |
|
|
|
case 0x0A: |
|
|
@ -165,7 +162,8 @@ var Parser = (function ParserClosure() { |
|
|
|
var followingBytes = stream.peekBytes(5); |
|
|
|
var followingBytes = stream.peekBytes(5); |
|
|
|
for (i = 0, ii = followingBytes.length; i < ii; i++) { |
|
|
|
for (i = 0, ii = followingBytes.length; i < ii; i++) { |
|
|
|
ch = followingBytes[i]; |
|
|
|
ch = followingBytes[i]; |
|
|
|
if (ch !== 0x0A && ch != 0x0D && (ch < 0x20 || ch > 0x7F)) { |
|
|
|
if (ch !== 0x0A && ch !== 0x0D && (ch < 0x20 || ch > 0x7F)) { |
|
|
|
|
|
|
|
// not a LF, CR, SPACE or any visible ASCII character
|
|
|
|
state = 0; |
|
|
|
state = 0; |
|
|
|
break; // some binary stuff found, resetting the state
|
|
|
|
break; // some binary stuff found, resetting the state
|
|
|
|
} |
|
|
|
} |
|
|
@ -206,7 +204,7 @@ var Parser = (function ParserClosure() { |
|
|
|
|
|
|
|
|
|
|
|
// get stream start position
|
|
|
|
// get stream start position
|
|
|
|
lexer.skipToNextLine(); |
|
|
|
lexer.skipToNextLine(); |
|
|
|
var pos = stream.pos; |
|
|
|
var pos = stream.pos - 1; |
|
|
|
|
|
|
|
|
|
|
|
// get length
|
|
|
|
// get length
|
|
|
|
var length = this.fetchIfRef(dict.get('Length')); |
|
|
|
var length = this.fetchIfRef(dict.get('Length')); |
|
|
@ -215,6 +213,8 @@ var Parser = (function ParserClosure() { |
|
|
|
|
|
|
|
|
|
|
|
// skip over the stream data
|
|
|
|
// skip over the stream data
|
|
|
|
stream.pos = pos + length; |
|
|
|
stream.pos = pos + length; |
|
|
|
|
|
|
|
lexer.nextChar(); |
|
|
|
|
|
|
|
|
|
|
|
this.shift(); // '>>'
|
|
|
|
this.shift(); // '>>'
|
|
|
|
this.shift(); // 'stream'
|
|
|
|
this.shift(); // 'stream'
|
|
|
|
if (!isCmd(this.buf1, 'endstream')) { |
|
|
|
if (!isCmd(this.buf1, 'endstream')) { |
|
|
@ -254,6 +254,8 @@ var Parser = (function ParserClosure() { |
|
|
|
error('Missing endstream'); |
|
|
|
error('Missing endstream'); |
|
|
|
} |
|
|
|
} |
|
|
|
length = skipped; |
|
|
|
length = skipped; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lexer.nextChar(); |
|
|
|
this.shift(); |
|
|
|
this.shift(); |
|
|
|
this.shift(); |
|
|
|
this.shift(); |
|
|
|
} |
|
|
|
} |
|
|
@ -344,6 +346,8 @@ var Parser = (function ParserClosure() { |
|
|
|
var Lexer = (function LexerClosure() { |
|
|
|
var Lexer = (function LexerClosure() { |
|
|
|
function Lexer(stream, knownCommands) { |
|
|
|
function Lexer(stream, knownCommands) { |
|
|
|
this.stream = stream; |
|
|
|
this.stream = stream; |
|
|
|
|
|
|
|
this.nextChar(); |
|
|
|
|
|
|
|
|
|
|
|
// The PDFs might have "glued" commands with other commands, operands or
|
|
|
|
// The PDFs might have "glued" commands with other commands, operands or
|
|
|
|
// literals, e.g. "q1". The knownCommands is a dictionary of the valid
|
|
|
|
// literals, e.g. "q1". The knownCommands is a dictionary of the valid
|
|
|
|
// commands and their prefixes. The prefixes are built the following way:
|
|
|
|
// commands and their prefixes. The prefixes are built the following way:
|
|
|
@ -355,7 +359,8 @@ var Lexer = (function LexerClosure() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Lexer.isSpace = function Lexer_isSpace(ch) { |
|
|
|
Lexer.isSpace = function Lexer_isSpace(ch) { |
|
|
|
return ch == ' ' || ch == '\t' || ch == '\x0d' || ch == '\x0a'; |
|
|
|
// space is one of the following characters: SPACE, TAB, CR, or LF
|
|
|
|
|
|
|
|
return ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// A '1' in this array means the character is white space. A '1' or
|
|
|
|
// A '1' in this array means the character is white space. A '1' or
|
|
|
@ -380,36 +385,40 @@ var Lexer = (function LexerClosure() { |
|
|
|
]; |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
function toHexDigit(ch) { |
|
|
|
function toHexDigit(ch) { |
|
|
|
if (ch >= '0' && ch <= '9') |
|
|
|
if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
|
|
|
|
return ch.charCodeAt(0) - 48; |
|
|
|
return ch & 0x0F; |
|
|
|
ch = ch.toUpperCase(); |
|
|
|
} |
|
|
|
if (ch >= 'A' && ch <= 'F') |
|
|
|
if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) { |
|
|
|
return ch.charCodeAt(0) - 55; |
|
|
|
// 'A'-'F', 'a'-'f'
|
|
|
|
|
|
|
|
return (ch & 0x0F) + 9; |
|
|
|
|
|
|
|
} |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Lexer.prototype = { |
|
|
|
Lexer.prototype = { |
|
|
|
getNumber: function Lexer_getNumber(ch) { |
|
|
|
nextChar: function Lexer_nextChar() { |
|
|
|
|
|
|
|
return (this.currentChar = this.stream.getByte()); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
getNumber: function Lexer_getNumber() { |
|
|
|
var floating = false; |
|
|
|
var floating = false; |
|
|
|
var str = ch; |
|
|
|
var ch = this.currentChar; |
|
|
|
var stream = this.stream; |
|
|
|
var str = String.fromCharCode(ch); |
|
|
|
while ((ch = stream.lookChar())) { |
|
|
|
while ((ch = this.nextChar()) >= 0) { |
|
|
|
if (ch == '.' && !floating) { |
|
|
|
if (ch === 0x2E && !floating) { // '.'
|
|
|
|
str += ch; |
|
|
|
str += '.'; |
|
|
|
floating = true; |
|
|
|
floating = true; |
|
|
|
} else if (ch == '-') { |
|
|
|
} else if (ch === 0x2D) { // '-'
|
|
|
|
// ignore minus signs in the middle of numbers to match
|
|
|
|
// ignore minus signs in the middle of numbers to match
|
|
|
|
// Adobe's behavior
|
|
|
|
// Adobe's behavior
|
|
|
|
warn('Badly formated number'); |
|
|
|
warn('Badly formated number'); |
|
|
|
} else if (ch >= '0' && ch <= '9') { |
|
|
|
} else if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
|
|
|
|
str += ch; |
|
|
|
str += String.fromCharCode(ch); |
|
|
|
} else if (ch == 'e' || ch == 'E') { |
|
|
|
} else if (ch === 0x45 || ch === 0x65) { // 'E', 'e'
|
|
|
|
floating = true; |
|
|
|
floating = true; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// the last character doesn't belong to us
|
|
|
|
// the last character doesn't belong to us
|
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
stream.skip(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
var value = parseFloat(str); |
|
|
|
var value = parseFloat(str); |
|
|
|
if (isNaN(value)) |
|
|
|
if (isNaN(value)) |
|
|
@ -420,148 +429,150 @@ var Lexer = (function LexerClosure() { |
|
|
|
var numParen = 1; |
|
|
|
var numParen = 1; |
|
|
|
var done = false; |
|
|
|
var done = false; |
|
|
|
var str = ''; |
|
|
|
var str = ''; |
|
|
|
var stream = this.stream; |
|
|
|
|
|
|
|
var ch; |
|
|
|
var ch = this.nextChar(); |
|
|
|
do { |
|
|
|
while (true) { |
|
|
|
ch = stream.getChar(); |
|
|
|
var charBuffered = false; |
|
|
|
switch (ch) { |
|
|
|
switch (ch | 0) { |
|
|
|
case null: |
|
|
|
case -1: |
|
|
|
case undefined: |
|
|
|
|
|
|
|
warn('Unterminated string'); |
|
|
|
warn('Unterminated string'); |
|
|
|
done = true; |
|
|
|
done = true; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '(': |
|
|
|
case 0x28: // '('
|
|
|
|
++numParen; |
|
|
|
++numParen; |
|
|
|
str += ch; |
|
|
|
str += '('; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case ')': |
|
|
|
case 0x29: // ')'
|
|
|
|
if (--numParen === 0) { |
|
|
|
if (--numParen === 0) { |
|
|
|
|
|
|
|
this.nextChar(); // consume strings ')'
|
|
|
|
done = true; |
|
|
|
done = true; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
str += ch; |
|
|
|
str += ')'; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '\\': |
|
|
|
case 0x5C: // '\\'
|
|
|
|
ch = stream.getChar(); |
|
|
|
ch = this.nextChar(); |
|
|
|
switch (ch) { |
|
|
|
switch (ch) { |
|
|
|
case null: |
|
|
|
case -1: |
|
|
|
case undefined: |
|
|
|
|
|
|
|
warn('Unterminated string'); |
|
|
|
warn('Unterminated string'); |
|
|
|
done = true; |
|
|
|
done = true; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case 'n': |
|
|
|
case 0x6E: // 'n'
|
|
|
|
str += '\n'; |
|
|
|
str += '\n'; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case 'r': |
|
|
|
case 0x72: // 'r'
|
|
|
|
str += '\r'; |
|
|
|
str += '\r'; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case 't': |
|
|
|
case 0x74: // 't'
|
|
|
|
str += '\t'; |
|
|
|
str += '\t'; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case 'b': |
|
|
|
case 0x62: // 'b'
|
|
|
|
str += '\b'; |
|
|
|
str += '\b'; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case 'f': |
|
|
|
case 0x66: // 'f'
|
|
|
|
str += '\f'; |
|
|
|
str += '\f'; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '\\': |
|
|
|
case 0x5C: // '\'
|
|
|
|
case '(': |
|
|
|
case 0x28: // '('
|
|
|
|
case ')': |
|
|
|
case 0x29: // ')'
|
|
|
|
str += ch; |
|
|
|
str += String.fromCharCode(ch); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '0': case '1': case '2': case '3': |
|
|
|
case 0x30: case 0x31: case 0x32: case 0x33: // '0'-'3'
|
|
|
|
case '4': case '5': case '6': case '7': |
|
|
|
case 0x34: case 0x35: case 0x36: case 0x37: // '4'-'7'
|
|
|
|
var x = ch - '0'; |
|
|
|
var x = ch & 0x0F; |
|
|
|
ch = stream.lookChar(); |
|
|
|
ch = this.nextChar(); |
|
|
|
if (ch >= '0' && ch <= '7') { |
|
|
|
charBuffered = true; |
|
|
|
stream.skip(); |
|
|
|
if (ch >= 0x30 && ch <= 0x37) { // '0'-'7'
|
|
|
|
x = (x << 3) + (ch - '0'); |
|
|
|
x = (x << 3) + (ch & 0x0F); |
|
|
|
ch = stream.lookChar(); |
|
|
|
ch = this.nextChar(); |
|
|
|
if (ch >= '0' && ch <= '7') { |
|
|
|
if (ch >= 0x30 && ch <= 0x37) { // '0'-'7'
|
|
|
|
stream.skip(); |
|
|
|
charBuffered = false; |
|
|
|
x = (x << 3) + (ch - '0'); |
|
|
|
x = (x << 3) + (ch & 0x0F); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
str += String.fromCharCode(x); |
|
|
|
str += String.fromCharCode(x); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case '\r': |
|
|
|
case 0x0A: case 0x0D: // LF, CR
|
|
|
|
ch = stream.lookChar(); |
|
|
|
|
|
|
|
if (ch == '\n') |
|
|
|
|
|
|
|
stream.skip(); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case '\n': |
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
|
default: |
|
|
|
default: |
|
|
|
str += ch; |
|
|
|
str += String.fromCharCode(ch); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
default: |
|
|
|
default: |
|
|
|
str += ch; |
|
|
|
str += String.fromCharCode(ch); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (done) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} while (!done); |
|
|
|
if (!charBuffered) { |
|
|
|
|
|
|
|
ch = this.nextChar(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
return str; |
|
|
|
return str; |
|
|
|
}, |
|
|
|
}, |
|
|
|
getName: function Lexer_getName(ch) { |
|
|
|
getName: function Lexer_getName() { |
|
|
|
var str = ''; |
|
|
|
var str = '', ch; |
|
|
|
var stream = this.stream; |
|
|
|
while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) { |
|
|
|
while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) { |
|
|
|
if (ch === 0x23) { // '#'
|
|
|
|
stream.skip(); |
|
|
|
ch = this.nextChar(); |
|
|
|
if (ch == '#') { |
|
|
|
|
|
|
|
ch = stream.lookChar(); |
|
|
|
|
|
|
|
var x = toHexDigit(ch); |
|
|
|
var x = toHexDigit(ch); |
|
|
|
if (x != -1) { |
|
|
|
if (x != -1) { |
|
|
|
stream.skip(); |
|
|
|
var x2 = toHexDigit(this.nextChar()); |
|
|
|
var x2 = toHexDigit(stream.getChar()); |
|
|
|
|
|
|
|
if (x2 == -1) |
|
|
|
if (x2 == -1) |
|
|
|
error('Illegal digit in hex char in name: ' + x2); |
|
|
|
error('Illegal digit in hex char in name: ' + x2); |
|
|
|
str += String.fromCharCode((x << 4) | x2); |
|
|
|
str += String.fromCharCode((x << 4) | x2); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
str += '#'; |
|
|
|
str += '#'; |
|
|
|
str += ch; |
|
|
|
str += String.fromCharCode(ch); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
str += ch; |
|
|
|
str += String.fromCharCode(ch); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (str.length > 128) |
|
|
|
if (str.length > 128) { |
|
|
|
error('Warning: name token is longer than allowed by the spec: ' + |
|
|
|
error('Warning: name token is longer than allowed by the spec: ' + |
|
|
|
str.length); |
|
|
|
str.length); |
|
|
|
|
|
|
|
} |
|
|
|
return new Name(str); |
|
|
|
return new Name(str); |
|
|
|
}, |
|
|
|
}, |
|
|
|
getHexString: function Lexer_getHexString(ch) { |
|
|
|
getHexString: function Lexer_getHexString() { |
|
|
|
var str = ''; |
|
|
|
var str = ''; |
|
|
|
var stream = this.stream; |
|
|
|
var ch = this.currentChar; |
|
|
|
var isFirstHex = true; |
|
|
|
var isFirstHex = true; |
|
|
|
var firstDigit; |
|
|
|
var firstDigit; |
|
|
|
var secondDigit; |
|
|
|
var secondDigit; |
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
ch = stream.getChar(); |
|
|
|
if (ch < 0) { |
|
|
|
if (!ch) { |
|
|
|
|
|
|
|
warn('Unterminated hex string'); |
|
|
|
warn('Unterminated hex string'); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} else if (ch === '>') { |
|
|
|
} else if (ch === 0x3E) { // '>'
|
|
|
|
|
|
|
|
this.nextChar(); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} else if (specialChars[ch.charCodeAt(0)] === 1) { |
|
|
|
} else if (specialChars[ch] === 1) { |
|
|
|
|
|
|
|
ch = this.nextChar(); |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if (isFirstHex) { |
|
|
|
if (isFirstHex) { |
|
|
|
firstDigit = toHexDigit(ch); |
|
|
|
firstDigit = toHexDigit(ch); |
|
|
|
if (firstDigit === -1) { |
|
|
|
if (firstDigit === -1) { |
|
|
|
warn('Ignoring invalid character "' + ch + '" in hex string'); |
|
|
|
warn('Ignoring invalid character "' + ch + '" in hex string'); |
|
|
|
|
|
|
|
ch = this.nextChar(); |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
secondDigit = toHexDigit(ch); |
|
|
|
secondDigit = toHexDigit(ch); |
|
|
|
if (secondDigit === -1) { |
|
|
|
if (secondDigit === -1) { |
|
|
|
warn('Ignoring invalid character "' + ch + '" in hex string'); |
|
|
|
warn('Ignoring invalid character "' + ch + '" in hex string'); |
|
|
|
|
|
|
|
ch = this.nextChar(); |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
str += String.fromCharCode((firstDigit << 4) | secondDigit); |
|
|
|
str += String.fromCharCode((firstDigit << 4) | secondDigit); |
|
|
|
} |
|
|
|
} |
|
|
|
isFirstHex = !isFirstHex; |
|
|
|
isFirstHex = !isFirstHex; |
|
|
|
|
|
|
|
ch = this.nextChar(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return str; |
|
|
|
return str; |
|
|
@ -569,73 +580,81 @@ var Lexer = (function LexerClosure() { |
|
|
|
getObj: function Lexer_getObj() { |
|
|
|
getObj: function Lexer_getObj() { |
|
|
|
// skip whitespace and comments
|
|
|
|
// skip whitespace and comments
|
|
|
|
var comment = false; |
|
|
|
var comment = false; |
|
|
|
var stream = this.stream; |
|
|
|
var ch = this.currentChar; |
|
|
|
var ch; |
|
|
|
|
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
if (!(ch = stream.getChar())) |
|
|
|
if (ch < 0) { |
|
|
|
return EOF; |
|
|
|
return EOF; |
|
|
|
|
|
|
|
} |
|
|
|
if (comment) { |
|
|
|
if (comment) { |
|
|
|
if (ch == '\r' || ch == '\n') |
|
|
|
if (ch === 0x0A || ch == 0x0D) // LF, CR
|
|
|
|
comment = false; |
|
|
|
comment = false; |
|
|
|
} else if (ch == '%') { |
|
|
|
} else if (ch === 0x25) { // '%'
|
|
|
|
comment = true; |
|
|
|
comment = true; |
|
|
|
} else if (specialChars[ch.charCodeAt(0)] != 1) { |
|
|
|
} else if (specialChars[ch] !== 1) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
ch = this.nextChar(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// start reading token
|
|
|
|
// start reading token
|
|
|
|
switch (ch) { |
|
|
|
switch (ch | 0) { |
|
|
|
case '0': case '1': case '2': case '3': case '4': |
|
|
|
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'
|
|
|
|
case '5': case '6': case '7': case '8': case '9': |
|
|
|
case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'
|
|
|
|
case '+': case '-': case '.': |
|
|
|
case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'
|
|
|
|
return this.getNumber(ch); |
|
|
|
return this.getNumber(); |
|
|
|
case '(': |
|
|
|
case 0x28: // '('
|
|
|
|
return this.getString(); |
|
|
|
return this.getString(); |
|
|
|
case '/': |
|
|
|
case 0x2F: // '/'
|
|
|
|
return this.getName(ch); |
|
|
|
return this.getName(); |
|
|
|
// array punctuation
|
|
|
|
// array punctuation
|
|
|
|
case '[': |
|
|
|
case 0x5B: // '['
|
|
|
|
case ']': |
|
|
|
this.nextChar(); |
|
|
|
return Cmd.get(ch); |
|
|
|
return Cmd.get('['); |
|
|
|
|
|
|
|
case 0x5D: // ']'
|
|
|
|
|
|
|
|
this.nextChar(); |
|
|
|
|
|
|
|
return Cmd.get(']'); |
|
|
|
// hex string or dict punctuation
|
|
|
|
// hex string or dict punctuation
|
|
|
|
case '<': |
|
|
|
case 0x3C: // '<'
|
|
|
|
ch = stream.lookChar(); |
|
|
|
ch = this.nextChar(); |
|
|
|
if (ch == '<') { |
|
|
|
if (ch === 0x3C) { |
|
|
|
// dict punctuation
|
|
|
|
// dict punctuation
|
|
|
|
stream.skip(); |
|
|
|
this.nextChar(); |
|
|
|
return Cmd.get('<<'); |
|
|
|
return Cmd.get('<<'); |
|
|
|
} |
|
|
|
} |
|
|
|
return this.getHexString(ch); |
|
|
|
return this.getHexString(); |
|
|
|
// dict punctuation
|
|
|
|
// dict punctuation
|
|
|
|
case '>': |
|
|
|
case 0x3E: // '>'
|
|
|
|
ch = stream.lookChar(); |
|
|
|
ch = this.nextChar(); |
|
|
|
if (ch == '>') { |
|
|
|
if (ch === 0x3E) { |
|
|
|
stream.skip(); |
|
|
|
this.nextChar(); |
|
|
|
return Cmd.get('>>'); |
|
|
|
return Cmd.get('>>'); |
|
|
|
} |
|
|
|
} |
|
|
|
return Cmd.get(ch); |
|
|
|
return Cmd.get('>'); |
|
|
|
case '{': |
|
|
|
case 0x7B: // '{'
|
|
|
|
case '}': |
|
|
|
this.nextChar(); |
|
|
|
return Cmd.get(ch); |
|
|
|
return Cmd.get('{'); |
|
|
|
// fall through
|
|
|
|
case 0x7D: // '}'
|
|
|
|
case ')': |
|
|
|
this.nextChar(); |
|
|
|
|
|
|
|
return Cmd.get('}'); |
|
|
|
|
|
|
|
case 0x29: // ')'
|
|
|
|
error('Illegal character: ' + ch); |
|
|
|
error('Illegal character: ' + ch); |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// command
|
|
|
|
// command
|
|
|
|
var str = ch; |
|
|
|
var str = String.fromCharCode(ch); |
|
|
|
var knownCommands = this.knownCommands; |
|
|
|
var knownCommands = this.knownCommands; |
|
|
|
var knownCommandFound = knownCommands && (str in knownCommands); |
|
|
|
var knownCommandFound = knownCommands && (str in knownCommands); |
|
|
|
while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) { |
|
|
|
while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) { |
|
|
|
// stop if known command is found and next character does not make
|
|
|
|
// stop if known command is found and next character does not make
|
|
|
|
// the str a command
|
|
|
|
// the str a command
|
|
|
|
if (knownCommandFound && !((str + ch) in knownCommands)) |
|
|
|
var possibleCommand = str + String.fromCharCode(ch); |
|
|
|
|
|
|
|
if (knownCommandFound && !(possibleCommand in knownCommands)) { |
|
|
|
break; |
|
|
|
break; |
|
|
|
stream.skip(); |
|
|
|
} |
|
|
|
if (str.length == 128) |
|
|
|
if (str.length == 128) |
|
|
|
error('Command token too long: ' + str.length); |
|
|
|
error('Command token too long: ' + str.length); |
|
|
|
str += ch; |
|
|
|
str = possibleCommand; |
|
|
|
knownCommandFound = knownCommands && (str in knownCommands); |
|
|
|
knownCommandFound = knownCommands && (str in knownCommands); |
|
|
|
} |
|
|
|
} |
|
|
|
if (str == 'true') |
|
|
|
if (str == 'true') |
|
|
@ -648,19 +667,20 @@ var Lexer = (function LexerClosure() { |
|
|
|
}, |
|
|
|
}, |
|
|
|
skipToNextLine: function Lexer_skipToNextLine() { |
|
|
|
skipToNextLine: function Lexer_skipToNextLine() { |
|
|
|
var stream = this.stream; |
|
|
|
var stream = this.stream; |
|
|
|
while (true) { |
|
|
|
var ch = this.currentChar; |
|
|
|
var ch = stream.getChar(); |
|
|
|
while (ch >= 0) { |
|
|
|
if (!ch || ch == '\n') |
|
|
|
if (ch === 0x0D) { // CR
|
|
|
|
return; |
|
|
|
ch = this.nextChar(); |
|
|
|
if (ch == '\r') { |
|
|
|
if (ch === 0x0A) { // LF
|
|
|
|
if ((ch = stream.lookChar()) == '\n') |
|
|
|
this.nextChar(); |
|
|
|
stream.skip(); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} else if (ch === 0x0A) { // LF
|
|
|
|
|
|
|
|
this.nextChar(); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ch = this.nextChar(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
skip: function Lexer_skip() { |
|
|
|
|
|
|
|
this.stream.skip(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|