public abstract class AbstractPreprocessorEnumerator : InputElementEnumerator { protected bool Verbose = false; protected bool emitting; protected System.Collections.Hashtable table; protected InputElementEnumerator iee; protected AbstractPreprocessorEnumerator subordinate; protected int linedelta; protected string file; public AbstractPreprocessorEnumerator(InputElementEnumerator iee) { this.iee = iee; linedelta = 0; } public override InputElement Current { get { return iee.Current; } } public override bool MoveNext() { // System.Console.WriteLine("MoveNext[" + this.ToString() + "]"); if (subordinate != null) { if (subordinate.MoveNext()) { return true; } subordinate = null; } return _moveNext(); } protected abstract bool _moveNext(); protected void tokenize(InputElement ie) { String2CharEnumerator s2ce = new String2CharEnumerator(ie.str); PreprocessorInputElementEnumerator pp = new PreprocessorInputElementEnumerator(s2ce, ie.coord.file); SkipWhiteEnumerator swe = new SkipWhiteEnumerator(pp); tokens = swe; if (Verbose) { tokens = new EchoInputEnumerator(tokens, "PPD> "); } } protected InputElementEnumerator tokens; protected void doLine() { if (!tokens.MoveNext()) { error("incomplete #line"); return; } if (tokens.Current.tag != "integer-literal") { error("expecting integer"); return; } string line = tokens.Current.str; if (emitting) { try { this.linedelta = System.Convert.ToInt32(line) - iee.Current.coord.line; } catch (System.OverflowException) { error("line number too big"); } } if (!tokens.MoveNext()) { return; } if (tokens.Current.tag == "") { return; } if (tokens.Current.tag != "string-literal") { error("expecting string"); } file = tokens.Current.str; } protected void doWarning() { if (emitting) { } } protected void doError() { if (emitting) { } } protected void doDefine() { if (!tokens.MoveNext()) { error("incomplete #define"); return; } if (tokens.Current.tag != "identifier") { error("expecting identifier"); return; } if (emitting) { table.Add(tokens.Current.str, tokens.Current.str); } } protected void doPragma() { if (!tokens.MoveNext()) { error("incomplete #pragma"); return; } if (tokens.Current.str != "warning") { error("expecting warning"); return; } if (!tokens.MoveNext()) { error("incomplete #pragma"); return; } switch (tokens.Current.str) { case "disable": case "restore": break; default : error("expecting disable or restore"); return; } if (!tokens.MoveNext()) { error("incomplete #pragma"); return; } // now we are at the error number } protected void doUndef() { if (!tokens.MoveNext()) { error("incomplete #undefine"); return; } if (tokens.Current.tag != "identifier") { error("expecting identifier"); return; } if (emitting) { table.Remove(tokens.Current.str); } } protected void error(string str) { System.Console.WriteLine("line " + iee.Current.coord.line + ": Preprocessor Error: " + str); } protected bool eval() { if (!tokens.MoveNext()) { error("incomplete expression"); return true; } return e1(); } bool e1() { bool v; v = e2(); while (tokens.Current.tag == "||") { if (!tokens.MoveNext()) { error("incomplete expression"); return true; } v |= e2(); } return v; } bool e2() { bool v; v = e3(); while (tokens.Current.tag == "&&") { if (!tokens.MoveNext()) { error("incomplete expression"); return true; } v &= e3(); } return v; } bool e3() { bool v; v = e4(); for (;;) { switch (tokens.Current.tag) { case "==": if (!tokens.MoveNext()) { error("incomplete expression"); return true; } v = (v == e4()); break; case "!=": if (!tokens.MoveNext()) { error("incomplete expression"); return true; } v = (v != e4()); break; default: return v; } } } bool e4() { if (tokens.Current.tag == "!") { if (!tokens.MoveNext()) { error("incomplete expression"); return true; } return !e4(); } return e5(); } bool e5() { bool v; switch (tokens.Current.tag) { case "true": return true; case "false": return false; case "(": if (!tokens.MoveNext()) { error("incomplete expression"); return true; } v = e1(); if (tokens.Current.tag != ")") { error("incomplete expression"); return true; } if (!tokens.MoveNext()) { error("incomplete expression"); return true; } return v; case "identifier": v = table.ContainsKey(tokens.Current.str); if (!tokens.MoveNext()) { error("incomplete expression"); return true; } return v; } error("invalid expression"); return true; } } public class PreprocessorEnumerator : AbstractPreprocessorEnumerator { public PreprocessorEnumerator(InputElementEnumerator iee) : base(iee) { this.table = new System.Collections.Hashtable(); this.emitting = true; } public PreprocessorEnumerator(InputElementEnumerator iee, bool Verbose) : this(iee) { this.Verbose = Verbose; } protected override bool _moveNext() { System.Diagnostics.Trace.Assert(emitting); while (iee.MoveNext()) { if (iee.Current.tag != "PREPROC") { iee.Current.coord.line += linedelta; if (file != null) { iee.Current.coord.file = file; } return true; } tokenize(iee.Current); bool status = tokens.MoveNext(); switch (tokens.Current.tag) { default: error("unknown preprocessor command: " + tokens.Current.tag); break; case "define": doDefine(); break; case "undef": doUndef(); break; case "line": doLine(); break; case "error": doError(); break; case "warning": doWarning(); break; case "region": subordinate = new RegionEnumerator(table, iee, emitting); if (subordinate.MoveNext()) { return true; } subordinate = null; continue; case "endregion": error("unexpected #endregion"); break; case "pragma": doPragma(); break; case "if": bool val = eval(); subordinate = new IfEnumerator(table, iee, emitting, val); if (subordinate.MoveNext()) { return true; } subordinate = null; continue; case "elif": error("unexpected #elif"); break; case "else": error("unexpected #else"); break; case "endif": error("unexpected #endif"); break; } } return false; } } public class RegionEnumerator : AbstractPreprocessorEnumerator { public RegionEnumerator(System.Collections.Hashtable table, InputElementEnumerator iee, bool emitting) : base(iee) { this.table = table; this.emitting = emitting; } protected override bool _moveNext() { while (iee.MoveNext()) { if (iee.Current.tag != "PREPROC") { if (emitting) { iee.Current.coord.line += linedelta; if (file != null) { iee.Current.coord.file = file; } return true; } continue; } tokenize(iee.Current); bool status = tokens.MoveNext(); switch (tokens.Current.tag) { default: error("unknown preprocessor command: " + tokens.Current.tag); break; case "define": doDefine(); break; case "undef": doUndef(); break; case "line": doLine(); break; case "error": doError(); break; case "warning": doWarning(); break; case "region": subordinate = new RegionEnumerator(table, iee, emitting); if (subordinate.MoveNext()) { return true; } subordinate = null; continue; case "endregion": return false; case "pragma": doPragma(); break; case "if": bool val = eval(); subordinate = new IfEnumerator(table, iee, emitting, val); if (subordinate.MoveNext()) { return true; } subordinate = null; continue; case "elif": error("unexpected #elif"); break; case "else": error("unexpected #else"); break; case "endif": error("unexpected #endif"); break; } } error("unfinished #region"); return false; } } public class IfEnumerator : AbstractPreprocessorEnumerator { public IfEnumerator(System.Collections.Hashtable table, InputElementEnumerator iee, bool emitting, bool conditional) : base(iee) { this.table = table; this.emitting = emitting; if (emitting) { this.conditional = conditional; this.condHistory = conditional; } else { this.conditional = false; this.condHistory = true; } } private bool conditional; private bool condHistory; protected override bool _moveNext() { while (iee.MoveNext()) { bool val; if (iee.Current.tag != "PREPROC") { if (conditional) { iee.Current.coord.line += linedelta; if (file != null) { iee.Current.coord.file = file; } return true; } continue; } tokenize(iee.Current); bool status = tokens.MoveNext(); switch (tokens.Current.tag) { default: error("unknown preprocessor command: " + tokens.Current.tag); break; case "define": doDefine(); break; case "undef": doUndef(); break; case "line": doLine(); break; case "error": doError(); break; case "warning": doWarning(); break; case "region": subordinate = new RegionEnumerator(table, iee, emitting && conditional); if (subordinate.MoveNext()) { return true; } subordinate = null; continue; case "endregion": error("unexpected #endregion"); break; case "pragma": doPragma(); break; case "if": val = eval(); subordinate = new IfEnumerator(table, iee, emitting && conditional, val); if (subordinate.MoveNext()) { return true; } subordinate = null; continue; case "elif": val = eval(); conditional = val && !condHistory; condHistory |= conditional; break; case "else": conditional = !condHistory; condHistory = true; continue; case "endif": return false; } } error("unfinished #if"); return false; } }