1023 lines
21 KiB
C#
1023 lines
21 KiB
C#
public class Char2InputElementEnumerator : InputElementEnumerator, System.Collections.IEnumerator {
|
|
protected int colno = 1;
|
|
protected int lineno = 1;
|
|
protected int startColumn = 0;
|
|
protected string file;
|
|
protected int fileOffset;
|
|
|
|
protected CharEnumerator ce;
|
|
private bool success;
|
|
private bool atEOI;
|
|
// private bool yieldEOF;
|
|
private InputElement buffered = null;
|
|
|
|
protected System.Text.StringBuilder tmp = new System.Text.StringBuilder();
|
|
|
|
public Char2InputElementEnumerator(CharEnumerator ce, string file) {
|
|
this.ce = ce;
|
|
this.file = file;
|
|
success = false;
|
|
// yieldEOF = false;
|
|
atEOI = !ce.MoveNext();
|
|
}
|
|
|
|
protected bool ret(string tag) {
|
|
return ret(tag, tag);
|
|
}
|
|
|
|
protected bool ret(string tag, string str) {
|
|
_current = new InputElement(tag, str, file, lineno, colno, file, fileOffset);
|
|
success = true;
|
|
return true;
|
|
}
|
|
|
|
protected bool ret(string tag, System.Text.StringBuilder buf) {
|
|
return ret(tag, buf.ToString());
|
|
}
|
|
|
|
protected bool malformed(string tag, string str) {
|
|
_current = new MalformedInputElement(new InputElement(tag, str, file, lineno, colno, file, fileOffset));
|
|
success = true;
|
|
return true;
|
|
}
|
|
|
|
protected bool malformed(string tag, System.Text.StringBuilder buf) {
|
|
return malformed(tag, buf.ToString());
|
|
}
|
|
|
|
|
|
public override bool MoveNext() {
|
|
string str;
|
|
|
|
if (buffered != null) {
|
|
_current = buffered;
|
|
buffered = null;
|
|
return true;
|
|
}
|
|
if (atEOI) {
|
|
// if (yieldEOF) {
|
|
// return success = false;
|
|
// }
|
|
// yieldEOF = true;
|
|
return ret("<EOF>");
|
|
}
|
|
colno = ce.Location - startColumn + 1;
|
|
fileOffset = ce.Location;
|
|
|
|
tmp.Length = 0;
|
|
switch (ce.Current) {
|
|
case '#':
|
|
return preproc();
|
|
case '"':
|
|
tmp.Append('"');
|
|
return stringLiteral();
|
|
case '\'':
|
|
tmp.Append('\'');
|
|
return characterLiteral();
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
return number();
|
|
|
|
case '\u0009':
|
|
nextchar();
|
|
return ret("WHITESPACE", "\u0009");
|
|
case '\u000b':
|
|
nextchar();
|
|
return ret("WHITESPACE", "\u000b");
|
|
case '\u000c':
|
|
nextchar();
|
|
return ret("WHITESPACE", "\u000c");
|
|
case '\u001a':
|
|
nextchar();
|
|
return ret("WHITESPACE", "\u001a");
|
|
case '\u000d':
|
|
str = "\u000d";
|
|
if (nextchar()) {
|
|
if (ce.Current == '\u000a') {
|
|
str = "\u000d\u000a";
|
|
nextchar();
|
|
}
|
|
}
|
|
startColumn = ce.Location;
|
|
lineno++;
|
|
return ret("NEWLINE", str);
|
|
case '\u000a':
|
|
nextchar();
|
|
startColumn = ce.Location;
|
|
lineno++;
|
|
return ret("NEWLINE", "\u000a");
|
|
case '\u2028':
|
|
nextchar();
|
|
startColumn = ce.Location;
|
|
lineno++;
|
|
return ret("NEWLINE", "\u2028");
|
|
case '\u2029':
|
|
nextchar();
|
|
startColumn = ce.Location;
|
|
lineno++;
|
|
return ret("NEWLINE", "\u2029");
|
|
case '/':
|
|
if (!nextchar()) {
|
|
return ret("/");
|
|
}
|
|
if (ce.Current == '=') {
|
|
nextchar();
|
|
return ret("/=");
|
|
}
|
|
tmp.Append("/");
|
|
if (ce.Current == '/') { // begin "//" comment
|
|
tmp.Append('/');
|
|
return slashslashComment();
|
|
}
|
|
if (ce.Current == '*') { // begin "/*" comment
|
|
tmp.Append('*');
|
|
return slashstarComment();
|
|
}
|
|
return ret("/");
|
|
case '.':
|
|
if (!nextchar()) {
|
|
return ret(".");
|
|
}
|
|
if (ce.Current < '0' || ce.Current > '9') {
|
|
return ret(".");
|
|
}
|
|
tmp.Append(".");
|
|
while (nextchar() && ce.Current >= '0' && ce.Current <= '9') {
|
|
tmp.Append(ce.Current);
|
|
}
|
|
return dotRealLiteral();
|
|
|
|
|
|
case '+':
|
|
if (!nextchar()) {
|
|
return ret("+");
|
|
}
|
|
switch (ce.Current) {
|
|
case '+':
|
|
nextchar();
|
|
return ret("++");
|
|
case '=':
|
|
nextchar();
|
|
return ret("+=");
|
|
default:
|
|
return ret("+");
|
|
}
|
|
case ';':
|
|
nextchar();
|
|
return ret(";");
|
|
case '[':
|
|
nextchar();
|
|
return ret("[");
|
|
case '{':
|
|
nextchar();
|
|
return ret("{");
|
|
case '(':
|
|
nextchar();
|
|
return ret("(");
|
|
case '%':
|
|
if (!nextchar()) {
|
|
return ret("%");
|
|
}
|
|
switch (ce.Current) {
|
|
case '=':
|
|
nextchar();
|
|
return ret("%=");
|
|
default:
|
|
return ret("%");
|
|
}
|
|
case '-':
|
|
if (!nextchar()) {
|
|
return ret("-");
|
|
}
|
|
switch (ce.Current) {
|
|
case '-':
|
|
nextchar();
|
|
return ret("--");
|
|
case '=':
|
|
nextchar();
|
|
return ret("-=");
|
|
case '>':
|
|
nextchar();
|
|
return ret("->");
|
|
default:
|
|
return ret("-");
|
|
}
|
|
case '=':
|
|
if (!nextchar()) {
|
|
return ret("=");
|
|
}
|
|
switch (ce.Current) {
|
|
case '=':
|
|
nextchar();
|
|
return ret("==");
|
|
default:
|
|
return ret("=");
|
|
}
|
|
case ']':
|
|
nextchar();
|
|
return ret("]");
|
|
case '}':
|
|
nextchar();
|
|
return ret("}");
|
|
case '*':
|
|
if (!nextchar()) {
|
|
return ret("*");
|
|
}
|
|
switch (ce.Current) {
|
|
case '=':
|
|
nextchar();
|
|
return ret("*=");
|
|
default:
|
|
return ret("*");
|
|
}
|
|
case ':':
|
|
if (!nextchar()) {
|
|
return ret(":");
|
|
}
|
|
switch (ce.Current) {
|
|
case ':':
|
|
nextchar();
|
|
return ret("::");
|
|
default:
|
|
return ret(":");
|
|
}
|
|
case '?':
|
|
nextchar();
|
|
return ret("?");
|
|
case ',':
|
|
nextchar();
|
|
return ret(",");
|
|
case '<':
|
|
if (!nextchar()) {
|
|
return ret("<");
|
|
}
|
|
switch (ce.Current) {
|
|
case '=':
|
|
nextchar();
|
|
return ret("<=");
|
|
case '<':
|
|
if (!nextchar()) {
|
|
return ret("<<");
|
|
}
|
|
switch (ce.Current) {
|
|
case '=':
|
|
nextchar();
|
|
return ret("<<=");
|
|
default:
|
|
return ret("<<");
|
|
}
|
|
default:
|
|
return ret("<");
|
|
}
|
|
case '|':
|
|
if (!nextchar()) {
|
|
return ret("|");
|
|
}
|
|
switch (ce.Current) {
|
|
case '=':
|
|
nextchar();
|
|
return ret("|=");
|
|
case '|':
|
|
nextchar();
|
|
return ret("||");
|
|
default:
|
|
return ret("|");
|
|
}
|
|
case '!':
|
|
if (!nextchar()) {
|
|
return ret("!");
|
|
}
|
|
switch (ce.Current) {
|
|
case '=':
|
|
nextchar();
|
|
return ret("!=");
|
|
default:
|
|
return ret("!");
|
|
}
|
|
case ')':
|
|
nextchar();
|
|
return ret(")");
|
|
case '&':
|
|
if (!nextchar()) {
|
|
return ret("&");
|
|
}
|
|
switch (ce.Current) {
|
|
case '=':
|
|
nextchar();
|
|
return ret("&=");
|
|
case '&':
|
|
nextchar();
|
|
return ret("&&");
|
|
default:
|
|
return ret("&");
|
|
}
|
|
case '>':
|
|
if (!nextchar()) {
|
|
return ret(">");
|
|
}
|
|
switch (ce.Current) {
|
|
case '=':
|
|
nextchar();
|
|
return ret(">=");
|
|
default:
|
|
return ret(">");
|
|
}
|
|
case '^':
|
|
if (!nextchar()) {
|
|
return ret("^");
|
|
}
|
|
switch (ce.Current) {
|
|
case '=':
|
|
nextchar();
|
|
return ret("^=");
|
|
default:
|
|
return ret("^");
|
|
}
|
|
case '~':
|
|
nextchar();
|
|
return ret("~");
|
|
}
|
|
|
|
if (UnicodeHelp.isZs(ce.Current)) {
|
|
string t = ce.Current.ToString();
|
|
t = System.String.Intern(t);
|
|
nextchar();
|
|
return ret("WHITESPACE", t);
|
|
}
|
|
|
|
// identifier, keyword, verbatim identifier, or verbatim string
|
|
if (ce.Current == '@') {
|
|
tmp.Append('@');
|
|
if (!nextchar()) {
|
|
return ret("UNRECOGNIZED", "@");
|
|
}
|
|
tmp.Append(ce.Current);
|
|
if (ce.Current == '"') {
|
|
return verbatimString();
|
|
}
|
|
return id_key(true);
|
|
}
|
|
if (UnicodeHelp.isLetterCharacter(ce.Current)
|
|
|| ce.Current == '_') {
|
|
tmp.Append(ce.Current);
|
|
return id_key(false);
|
|
}
|
|
|
|
str = ce.Current.ToString();
|
|
nextchar();
|
|
return ret("UNRECOGNIZED", str);
|
|
}
|
|
|
|
private bool verbatimString() {
|
|
int lineno = this.lineno;
|
|
for (;;) {
|
|
if (!nextchar()) {
|
|
return malformed("string-literal", tmp.ToString());
|
|
}
|
|
tmp.Append(ce.Current);
|
|
CONT:
|
|
switch (ce.Current) {
|
|
default:
|
|
break;
|
|
|
|
case '"':
|
|
if (!nextchar() || ce.Current != '"') {
|
|
bool b = ret("string-literal", tmp.ToString());
|
|
this.lineno = lineno;
|
|
return b;
|
|
}
|
|
tmp.Append(ce.Current);
|
|
break;
|
|
case '\u000d':
|
|
if (!nextchar()) {
|
|
lineno++;
|
|
startColumn = ce.Location+1;
|
|
bool b = malformed("string-literal", tmp);
|
|
this.lineno = lineno;
|
|
return b;
|
|
}
|
|
tmp.Append(ce.Current);
|
|
if (ce.Current != '\u000a') { // count new-line on the \u000a of \u000d\u000a
|
|
lineno++;
|
|
startColumn = ce.Location+1;
|
|
}
|
|
goto CONT; // evil, evil, evil!
|
|
case '\u000a':
|
|
case '\u2028':
|
|
case '\u2029':
|
|
lineno++;
|
|
startColumn = ce.Location+1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool dotRealLiteral() {
|
|
// START cut-n-paste
|
|
if (ce.Current == 'e' || ce.Current == 'E') {
|
|
tmp.Append(ce.Current);
|
|
if (!nextchar()) {
|
|
return malformed("real-literal", tmp.ToString());
|
|
}
|
|
if (ce.Current == '-' || ce.Current == '+') {
|
|
tmp.Append(ce.Current);
|
|
if (!nextchar()) {
|
|
return malformed("real-literal", tmp);
|
|
}
|
|
}
|
|
if (ce.Current < '0' || ce.Current > '9') {
|
|
return malformed("real-literal", tmp);
|
|
}
|
|
tmp.Append(ce.Current);
|
|
while (nextchar() && ce.Current >= '0' && ce.Current <= '9') {
|
|
tmp.Append(ce.Current);
|
|
}
|
|
}
|
|
realSuffix();
|
|
return ret("real-literal", tmp);
|
|
// END cut-n-paste
|
|
}
|
|
|
|
// identifier, verbatim identifier, or keyword
|
|
private bool id_key(bool verbatimFlag) {
|
|
bool errorFlag;
|
|
|
|
while (nextchar()) {
|
|
if (UnicodeHelp.isIdentifierPartCharacter(ce.Current)) {
|
|
tmp.Append(ce.Current);
|
|
continue;
|
|
}
|
|
if (ce.Current == '\\') {
|
|
tmp.Append(ce.Current);
|
|
if (!nextchar()) {
|
|
return malformed("identifier", tmp);
|
|
}
|
|
tmp.Append(ce.Current);
|
|
errorFlag = true;
|
|
char ch = unicodeEscape(ref errorFlag);
|
|
if (errorFlag) {
|
|
return malformed("identifier", tmp);
|
|
}
|
|
verbatimFlag = true;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (verbatimFlag) {
|
|
return ret("identifier", tmp);
|
|
}
|
|
string str = System.String.Intern(tmp.ToString());
|
|
string t = keyword(str);
|
|
if (t != null) {
|
|
return ret(t, t);
|
|
}
|
|
return ret("identifier", str);
|
|
}
|
|
|
|
protected virtual string keyword(string s) {
|
|
return KeywordHelp.keywordTag(s);
|
|
}
|
|
|
|
private bool slashstarComment() {
|
|
while (nextchar()) {
|
|
CONT: tmp.Append(ce.Current);
|
|
while (ce.Current == '*') { // evil
|
|
if (!nextchar()) {
|
|
return malformed("COMMENT", tmp);
|
|
}
|
|
tmp.Append(ce.Current);
|
|
if (ce.Current == '/') {
|
|
nextchar();
|
|
return ret("COMMENT", tmp);
|
|
}
|
|
}
|
|
switch (ce.Current) {
|
|
case '\u000d':
|
|
if (!nextchar()) {
|
|
lineno++;
|
|
startColumn = ce.Location;
|
|
return malformed("COMMENT", tmp);
|
|
}
|
|
if (ce.Current != '\u000a') { // count new-line on the \u000a of \u000d\u000a
|
|
lineno++;
|
|
startColumn = ce.Location;
|
|
}
|
|
goto CONT; // evil, evil, evil
|
|
case '\u000a':
|
|
case '\u2028':
|
|
case '\u2029':
|
|
lineno++;
|
|
startColumn = ce.Location;
|
|
break;
|
|
}
|
|
}
|
|
return malformed("COMMENT", tmp);
|
|
}
|
|
|
|
private bool slashslashComment() {
|
|
while (nextchar()) {
|
|
switch (ce.Current) {
|
|
case '\u000d':
|
|
case '\u000a':
|
|
case '\u2028':
|
|
case '\u2029':
|
|
return ret("COMMENT", tmp);
|
|
}
|
|
tmp.Append(ce.Current);
|
|
}
|
|
return ret("COMMENT", tmp);
|
|
}
|
|
|
|
private bool characterLiteral() {
|
|
bool errorFlag;
|
|
char tmpChar;
|
|
|
|
if (!nextchar()) {
|
|
return malformed("character-literal", tmp);
|
|
}
|
|
tmp.Append(ce.Current);
|
|
switch (ce.Current) {
|
|
case '\x0027':
|
|
return malformed("character-literal", tmp);
|
|
case '\u000d':
|
|
case '\u000a':
|
|
case '\u2028':
|
|
case '\u2029':
|
|
return malformed("character-literal", tmp);
|
|
case '\\':
|
|
errorFlag = false;
|
|
tmpChar = escapeChar(ref errorFlag);
|
|
if (errorFlag) {
|
|
return malformed("character-literal", tmp);
|
|
}
|
|
// tmp.Append(tmpChar);
|
|
if (atEOI) {
|
|
return malformed("character-literal", tmp);
|
|
}
|
|
if (ce.Current != '\'') {
|
|
return malformed("character-literal", tmp);
|
|
}
|
|
tmp.Append(ce.Current);
|
|
nextchar();
|
|
return ret("character-literal", tmp);
|
|
default:
|
|
if (!nextchar()) {
|
|
return malformed("character-literal", tmp);
|
|
}
|
|
if (ce.Current != '\'') {
|
|
return malformed("character-literal", tmp);
|
|
}
|
|
tmp.Append(ce.Current);
|
|
nextchar();
|
|
return ret("character-literal", tmp);
|
|
}
|
|
}
|
|
|
|
protected virtual bool stringLiteral() {
|
|
bool errorFlag;
|
|
char tmpChar;
|
|
|
|
if (!nextchar()) {
|
|
return malformed("string-literal", tmp);
|
|
}
|
|
for (;;) {
|
|
tmp.Append(ce.Current);
|
|
switch (ce.Current) {
|
|
case '\u000d':
|
|
case '\u000a':
|
|
case '\u2028':
|
|
case '\u2029':
|
|
return malformed("string-literal", tmp);
|
|
case '\\':
|
|
errorFlag = false;
|
|
tmpChar = escapeChar(ref errorFlag);
|
|
if (errorFlag) {
|
|
return malformed("string-literal", tmp);
|
|
}
|
|
// tmp.Append(tmpChar);
|
|
break;
|
|
case '"':
|
|
nextchar();
|
|
return ret("string-literal", tmp);
|
|
default:
|
|
if (!nextchar()) {
|
|
return malformed("string-literal", tmp);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool preproc() {
|
|
while (nextchar()) {
|
|
tmp.Append(ce.Current);
|
|
switch (ce.Current) {
|
|
case '\u000a':
|
|
case '\u2028':
|
|
case '\u2029':
|
|
nextchar();
|
|
startColumn = ce.Location;
|
|
lineno++;
|
|
return ret("PREPROC", tmp);
|
|
case '\u000d':
|
|
if (nextchar()) {
|
|
if (ce.Current == '\u000a') {
|
|
tmp.Append(ce.Current);
|
|
nextchar();
|
|
}
|
|
}
|
|
startColumn = ce.Location;
|
|
lineno++;
|
|
return ret("PREPROC", tmp);
|
|
}
|
|
|
|
}
|
|
return ret("PREPROC", tmp);
|
|
}
|
|
|
|
private bool number() {
|
|
if (ce.Current == '0') {
|
|
tmp.Append(ce.Current);
|
|
if (!nextchar()) {
|
|
// just zero
|
|
return ret("integer-literal", tmp);
|
|
}
|
|
if (ce.Current == 'x' || ce.Current == 'X') {
|
|
// hex literal
|
|
tmp.Append(ce.Current);
|
|
while (nextchar()) {
|
|
if ((ce.Current >= '0' && ce.Current <= '9') ||
|
|
(ce.Current >= 'a' && ce.Current <= 'f') ||
|
|
(ce.Current >= 'A' && ce.Current <= 'F')) {
|
|
tmp.Append(ce.Current);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
integerSuffix();
|
|
return ret("integer-literal", tmp);
|
|
}
|
|
}
|
|
while (ce.Current >= '0' && ce.Current <= '9') {
|
|
tmp.Append(ce.Current);
|
|
if (!nextchar()) {
|
|
return ret("integer-literal", tmp);
|
|
}
|
|
}
|
|
if (integerSuffix()) {
|
|
return ret("integer-literal", tmp);
|
|
}
|
|
if (realSuffix()) {
|
|
return ret("real-literal", tmp);
|
|
}
|
|
if (ce.Current == '.') {
|
|
if (!nextchar()) {
|
|
buffered = new InputElement(".", ".", file, lineno, colno, file, fileOffset);
|
|
return ret("integer-literal", tmp);
|
|
}
|
|
if (ce.Current < '0' || ce.Current > '9') {
|
|
buffered = new InputElement(".", ".", file, lineno, colno, file, fileOffset);
|
|
return ret("integer-literal", tmp);
|
|
}
|
|
tmp.Append('.');
|
|
tmp.Append(ce.Current);
|
|
while (nextchar() && ce.Current >= '0' && ce.Current <= '9') {
|
|
tmp.Append(ce.Current);
|
|
}
|
|
// START cut-n-paste
|
|
if (ce.Current == 'e' || ce.Current == 'E') {
|
|
tmp.Append(ce.Current);
|
|
if (!nextchar()) {
|
|
return malformed("real-literal", tmp);
|
|
}
|
|
if (ce.Current == '-' || ce.Current == '+') {
|
|
tmp.Append(ce.Current);
|
|
if (!nextchar()) {
|
|
return malformed("real-literal", tmp);
|
|
}
|
|
}
|
|
if (ce.Current < '0' || ce.Current > '9') {
|
|
return malformed("real-literal", tmp);
|
|
}
|
|
tmp.Append(ce.Current);
|
|
while (nextchar() && ce.Current >= '0' && ce.Current <= '9') {
|
|
tmp.Append(ce.Current);
|
|
}
|
|
}
|
|
realSuffix();
|
|
return ret("real-literal", tmp);
|
|
// END cut-n-paste
|
|
}
|
|
// START cut-n-paste
|
|
if (ce.Current == 'e' || ce.Current == 'E') {
|
|
tmp.Append(ce.Current);
|
|
if (!nextchar()) {
|
|
return malformed("real-literal", tmp);
|
|
}
|
|
if (ce.Current == '-' || ce.Current == '+') {
|
|
tmp.Append(ce.Current);
|
|
if (!nextchar()) {
|
|
return malformed("real-literal", tmp);
|
|
}
|
|
}
|
|
if (ce.Current < '0' || ce.Current > '9') {
|
|
return malformed("real-literal", tmp);
|
|
}
|
|
tmp.Append(ce.Current);
|
|
while (nextchar() && ce.Current >= '0' && ce.Current <= '9') {
|
|
tmp.Append(ce.Current);
|
|
}
|
|
realSuffix();
|
|
return ret("real-literal", tmp);
|
|
}
|
|
// END cut-n-paste almost
|
|
return ret("integer-literal", tmp);
|
|
}
|
|
|
|
private bool integerSuffix() {
|
|
if (ce.Current == 'u' || ce.Current == 'U') {
|
|
tmp.Append(ce.Current);
|
|
if (nextchar() && (ce.Current == 'l' || ce.Current == 'L')) {
|
|
tmp.Append(ce.Current);
|
|
nextchar();
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
if (ce.Current == 'l' || ce.Current == 'L') {
|
|
tmp.Append(ce.Current);
|
|
if (nextchar() && (ce.Current == 'u' || ce.Current == 'U')) {
|
|
tmp.Append(ce.Current);
|
|
nextchar();
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool realSuffix() {
|
|
switch (ce.Current) {
|
|
case 'M':
|
|
case 'm':
|
|
case 'D':
|
|
case 'd':
|
|
case 'F':
|
|
case 'f':
|
|
tmp.Append(ce.Current);
|
|
nextchar();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private char escapeChar(ref bool errorFlag) {
|
|
if (ce.Current != '\\') {
|
|
errorFlag = true;
|
|
return '\xffff';
|
|
}
|
|
if (!nextchar()) {
|
|
errorFlag = true;
|
|
return '\xffff';
|
|
}
|
|
tmp.Append(ce.Current);
|
|
switch (ce.Current) {
|
|
default:
|
|
errorFlag = true;
|
|
nextchar();
|
|
return '\xffff';
|
|
case '\'':
|
|
errorFlag = false;
|
|
nextchar();
|
|
return '\'';
|
|
case '\"':
|
|
errorFlag = false;
|
|
nextchar();
|
|
return '\"';
|
|
case '\\':
|
|
errorFlag = false;
|
|
nextchar();
|
|
return '\\';
|
|
case '0':
|
|
errorFlag = false;
|
|
nextchar();
|
|
return '\0';
|
|
case 'a':
|
|
errorFlag = false;
|
|
nextchar();
|
|
return '\a';
|
|
case 'b':
|
|
errorFlag = false;
|
|
nextchar();
|
|
return '\b';
|
|
case 'f':
|
|
errorFlag = false;
|
|
nextchar();
|
|
return '\f';
|
|
case 'n':
|
|
errorFlag = false;
|
|
nextchar();
|
|
return '\n';
|
|
case 'r':
|
|
errorFlag = false;
|
|
nextchar();
|
|
return '\r';
|
|
case 't':
|
|
errorFlag = false;
|
|
nextchar();
|
|
return '\t';
|
|
case 'v':
|
|
errorFlag = false;
|
|
nextchar();
|
|
return '\v';
|
|
case 'x':
|
|
errorFlag = false;
|
|
return hexEscape(ref errorFlag);
|
|
case 'u':
|
|
case 'U':
|
|
errorFlag = false;
|
|
char t = unicodeEscape(ref errorFlag);
|
|
nextchar();
|
|
return t;
|
|
}
|
|
}
|
|
|
|
private char hexEscape(ref bool errorFlag) {
|
|
if (ce.Current != 'x') {
|
|
errorFlag = true;
|
|
return '\uffff';
|
|
}
|
|
int acc = 0;
|
|
int count;
|
|
for (count = 0; nextchar() && count < 4; count++) {
|
|
switch (ce.Current) {
|
|
default:
|
|
break;
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
tmp.Append(ce.Current);
|
|
acc = (acc << 4) + ce.Current - '0';
|
|
continue;
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
tmp.Append(ce.Current);
|
|
acc = (acc << 4) + ce.Current - 'a' + 10;
|
|
continue;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
tmp.Append(ce.Current);
|
|
acc = (acc << 4) + ce.Current - 'A' + 10;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (count > 0) {
|
|
errorFlag = false;
|
|
return (char)acc;
|
|
}
|
|
errorFlag = true;
|
|
return '\uffff';
|
|
}
|
|
|
|
private char unicodeEscape(ref bool errorFlag) {
|
|
if (ce.Current != 'u' && ce.Current != 'U') {
|
|
errorFlag = true;
|
|
return '\uffff';
|
|
}
|
|
int len;
|
|
if (ce.Current == 'U') {
|
|
len = 8;
|
|
} else {
|
|
len = 4;
|
|
}
|
|
int acc = 0;
|
|
for (int i = 0; i < len; i++) {
|
|
if (!nextchar()) {
|
|
errorFlag = true;
|
|
return '\uffff';
|
|
}
|
|
tmp.Append(ce.Current);
|
|
switch (ce.Current) {
|
|
default:
|
|
errorFlag = true;
|
|
return '\uffff';
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
acc = (acc << 4) + ce.Current - '0';
|
|
break;
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
acc = (acc << 4) + ce.Current - 'a' + 10;
|
|
break;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
acc = (acc << 4) + ce.Current - 'A' + 10;
|
|
break;
|
|
}
|
|
}
|
|
errorFlag = false;
|
|
return (char)acc;
|
|
}
|
|
|
|
protected bool nextchar() {
|
|
if (ce.MoveNext()) {
|
|
return true;
|
|
} else {
|
|
atEOI = true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private InputElement _current;
|
|
public override InputElement Current {
|
|
get {
|
|
if (success) {
|
|
return _current;
|
|
} else {
|
|
throw new System.InvalidOperationException();
|
|
}
|
|
}
|
|
}
|
|
|
|
object System.Collections.IEnumerator.Current {
|
|
get {
|
|
return Current;
|
|
}
|
|
}
|
|
|
|
public virtual void Reset() {
|
|
}
|
|
}
|
|
|
|
public class PreprocessorInputElementEnumerator : Char2InputElementEnumerator {
|
|
public PreprocessorInputElementEnumerator(CharEnumerator ce, string file)
|
|
: base(ce, file) {
|
|
// do nothing special
|
|
}
|
|
|
|
protected override string keyword(string s) {
|
|
return PPKeywordHelp.keywordTag(s);
|
|
}
|
|
|
|
override protected bool stringLiteral() {
|
|
for (;;) {
|
|
if (!nextchar()) {
|
|
return malformed("string-literal", tmp);
|
|
}
|
|
switch (ce.Current) {
|
|
case '\u000d':
|
|
case '\u000a':
|
|
case '\u2028':
|
|
case '\u2029':
|
|
return malformed("string-literal", tmp);
|
|
case '"':
|
|
nextchar();
|
|
return ret("string-literal", tmp);
|
|
default:
|
|
tmp.Append(ce.Current);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|