/// <summary> /// Reads a quoted name with any character in it, until a '"' or '>' is found /// </summary> internal static Name ReadQuotedName(char c, TextStream S) { List <string> results = new List <string>(); string result = ""; // Read until we reach the closing '"' if (!S.EOT) { c = S.Pop(); while (c != CHAR_STRING_DELIMITER) { if (c == CHAR_CHILD_MARKER) { // Add a new string results.Add(result); result = ""; } else { result += c; } if (S.EOT) { break; } c = S.Pop(); } } results.Add(result); return(new Name(results.ToArray())); }
/// <summary> /// Reads a name while alphanumeric characters are found /// </summary> internal static Name Read(char c, TextStream S) { List <string> results = new List <string>(); string result = ""; while ((c == CHAR_CHILD_MARKER || c == CHAR_STRING_DELIMITER || c == CHAR_SPECIAL_STRING_DELIMITER_START || c == CHAR_SPECIAL_STRING_DELIMITER_END || IsAlphaNumeric(c))) { if (c == CHAR_STRING_DELIMITER) { // Read a quoted-name like "\"example\"" Name temp = ReadQuotedName(c, S); for (int i = 0; i < temp.m_name.Length - 1; i++) { results.Add(temp.m_name[i]); } result = temp.m_name[temp.m_name.Length - 1]; } else if (c == CHAR_SPECIAL_STRING_DELIMITER_START) { // Read a special-name like "<example>" result = "" + c; while ((c = S.Pop()) != CHAR_SPECIAL_STRING_DELIMITER_END) { result += c; } result += c; } else if (c == CHAR_CHILD_MARKER) { // Add a new string results.Add(result); result = ""; } else { result += c; } if (S.EOT) { break; } c = S.Pop(); } results.Add(result); S.GoBackOne(); return(new Name(results.ToArray())); }
/// <summary> /// Builds a name /// </summary> /// <param name="c"></param> /// <param name="S"></param> /// <returns></returns> public static Name Read(string _fullyQualifiedName) { if (_fullyQualifiedName == null || _fullyQualifiedName == "") { return(null); } TextStream S = new TextStream(_fullyQualifiedName); return(Read(S.Pop(), S)); }
public static string Read(TextStream S) { string result = ""; char c = S.Pop(); if (c == CHAR_COMMENT) { c = S.Pop(); } // Read until we reach EOL while (c != '\n') { if (c != '\r') { result += c; } c = S.Pop(); } return(result); }
public Parser(string _text) { m_stream = new TextStream(_text + "\n"); Push(STATE.COLLECTION); m_root = PushCollection(null); Name name = null; char c; // Last read character in the stream while (!m_stream.EOT) { c = m_stream.Pop(); // Get current character if (IsSpaceNoEOL(c)) { continue; // Skip space } if (c == CHAR_COMMENT) { // Read till the end of line CommentParser.Read(m_stream); if (m_state.Peek() == STATE.NAME) { // In NAME state, a new line acts as a collection item separator Pop(); } continue; } if (c == CHAR_PREPROCESSOR) { // Read till the end of line and keep for further parsing... Token T = AddToken(Token.TYPE.PREPROCESSOR_DIRECTIVE, null); T.m_value = CommentParser.Read(m_stream); continue; } switch (m_state.Peek()) { ////////////////////////////////////////////////////////////////////////// // In NAME state, we expect: // • an alias assignment // • a child assignment // • a feature assignment // • a constructor // • a collection end // case STATE.NAME: if (c == CHAR_COLLECTION_ITEM_SEPARATOR || c == '\n') { // A new line acts as a collection item separator, go back to previous state Pop(); continue; } else if (c == CHAR_ALIAS_ASSIGNMENT || c == '⇒') { // Check if it's an assignment or a parent-child definition if (c == '⇒' || m_stream.Peek == CHAR_HIERARCHY) { // Parent-Child hierarchy marker if (c != '⇒') { c = m_stream.Pop(); // Consume character } AddToken(Token.TYPE.HIERARCHY_MARKER, null); Pop(); Push(STATE.CHILD); continue; } // Last parsed name was in fact an alias MakeLastTokenA(Token.TYPE.ALIAS); Pop(); Push(STATE.ALIAS); continue; } else if (c == CHAR_FEATURES_COLLECTION_MARKER) { // Parent-Child features marker AddToken(Token.TYPE.FEATURE_MARKER, null); Pop(); Push(STATE.CHILD); continue; } else if (c == CHAR_CONSTRUCTOR_START) { // Entering constructor definition Token T = AddToken(Token.TYPE.CONSTRUCTOR, null); T.m_value = PushCollection(T); Pop(); Push(STATE.CONSTRUCTOR); continue; } else if (c == CHAR_COLLECTION_END) { // Exiting collection Pop(); // Pop name Pop(); // Pop collection PopCollection(); Push(STATE.NAME); // Assume an entire collection is a single name token continue; } SyntaxError(m_stream, c, "a name"); break; ////////////////////////////////////////////////////////////////////////// // In VALUE state, we expect: // • A value separator // • The end of the constructor // case STATE.VALUE: if (c == CHAR_COLLECTION_ITEM_SEPARATOR || c == '\n') { // A new line acts as a separator, go back to previous state Pop(); continue; } else if (c == CHAR_CONSTRUCTOR_END) { // Exit the constructor Pop(); // Pop value Pop(); // Pop constructor PopCollection(); Push(STATE.NAME); // Assume a constructed name is a single name token continue; } SyntaxError(m_stream, c, "a constructor value"); break; ////////////////////////////////////////////////////////////////////////// // In collection state, we expect: // • a name // • a collection start // • a collection end // • a separator // case STATE.COLLECTION: if (c == CHAR_COLLECTION_ITEM_SEPARATOR || c == '\n') { continue; } if (c == CHAR_COLLECTION_START) { // Start a new collection Token T = AddToken(Token.TYPE.COLLECTION, null); T.m_value = PushCollection(T); Push(STATE.COLLECTION); continue; } else if (c == CHAR_COLLECTION_END) { // Exit the collection Pop(); // Pop collection PopCollection(); Push(STATE.NAME); // Assume an entire collection is a single name token continue; } else if (ReadName(c, m_stream, ref name)) { // We just read a name AddToken(Token.TYPE.NAME, name); Push(STATE.NAME); continue; } SyntaxError(m_stream, c, "collection"); break; ////////////////////////////////////////////////////////////////////////// // In CONSTRUCTOR state, we expect: // • A value // • An alias name // • The end of the constructor // case STATE.CONSTRUCTOR: if (c == '\n') { continue; } if (c == CHAR_CONSTRUCTOR_END) { // Exit the constructor Pop(); // Pop constructor PopCollection(); Push(STATE.NAME); // Assume a constructed name is a single name token continue; } else if (ReadName(c, m_stream, ref name)) { // We just read a name and it MUST be an alias! AddToken(Token.TYPE.NAME, name); Push(STATE.NAME); continue; } SyntaxError(m_stream, c, "a constructor"); break; ////////////////////////////////////////////////////////////////////////// // In CHILD state, we expect: // • a new NAME // • a new collection // case STATE.CHILD: if (c == '\n') { continue; } if (c == CHAR_COLLECTION_START) { // Start a new collection Pop(); Token T = AddToken(Token.TYPE.COLLECTION, null); T.m_value = PushCollection(T); Push(STATE.COLLECTION); continue; } else if (ReadName(c, m_stream, ref name)) { // We just read a name Pop(); AddToken(Token.TYPE.NAME, name); Push(STATE.NAME); continue; } SyntaxError(m_stream, c, "child"); break; ////////////////////////////////////////////////////////////////////////// // In ALIAS state, we expect: // • a new NAME // case STATE.ALIAS: if (c == '\n') { continue; } if (ReadName(c, m_stream, ref name)) { // We just read a name Pop(); AddToken(Token.TYPE.NAME, name); Push(STATE.NAME); continue; } SyntaxError(m_stream, c, "an alias"); break; } } // Verify we're back to the root collection if (m_state.Count != 1) { throw new Exception("Leaving parsing with " + (m_state.Count - 1) + " states remaining, not at root level!"); } if (m_state.Peek() != STATE.COLLECTION) { throw new Exception("Leaving parsing with a single state that is not the root COLLECTION!"); } }