/// <summary> /// Interpreta un nodo /// </summary> private MLNode ParseNode(string strName, ParserTokenizer objTokenizer, bool blnSearchBracket) { MLNode objMLNode = new MLNode(strName); // Captura el siguiente nodo if (!objTokenizer.IsEof()) { if (blnSearchBracket) { // Obtiene el siguiente token GetNextToken(objTokenizer); // Debería ser una llave de apertura if (intIDActualType == TokenType.BraceOpen) objMLNode.Nodes.Add(ParseNodesArray(objTokenizer)); else if (intIDActualType != TokenType.BracketOpen) throw new ParserException("Se esperaba una llave de apertura"); else ParseNodeAttributes(objTokenizer, objMLNode); } else ParseNodeAttributes(objTokenizer, objMLNode); } // Devuelve el nodo interpretado return objMLNode; }
/// <summary> /// Interpreta los atributos de un nodo "id":"value","id":"value", ... ó "id":{object} ó "id":[array] /// </summary> private void ParseNodeAttributes(ParserTokenizer objTokenizer, MLNode objMLNodeParent) { bool blnEnd = false; // Obtiene los nodos while (!objTokenizer.IsEof() && !blnEnd) { // Lee el siguiente Token, debería ser un identificador GetNextToken(objTokenizer); // Comprueba que sea correcto if (intIDActualType == TokenType.BracketClose) // ... es un objeto vacío blnEnd = true; else if (intIDActualType != TokenType.String) // ... no se ha encontrado el identificador throw new ParserException("Se esperaba el identificador del elemento"); else { MLAttribute objMLAttribute = new MLAttribute(); // Asigna el código del atributo objMLAttribute.Name = objActualToken.Lexema; // Lee el siguiente token. Deberían ser dos puntos GetNextToken(objTokenizer); // Comprueba que sea correcto if (intIDActualType != TokenType.Colon) throw new ParserException("Se esperaban dos puntos (separador de identificador / valor)"); else { // Lee el siguiente token... GetNextToken(objTokenizer); // Interpreta el valor switch (intIDActualType) { case TokenType.String: case TokenType.True: case TokenType.False: case TokenType.Numeric: case TokenType.Null: // Asigna el valor al atributo switch (intIDActualType) { case TokenType.Null: objMLAttribute.Value = ""; break; case TokenType.String: objMLAttribute.Value = ParseUnicode(objActualToken.Lexema); break; default: objMLAttribute.Value = objActualToken.Lexema; break; } // Añade el atributo al nodo objMLNodeParent.Attributes.Add(objMLAttribute); break; case TokenType.BracketOpen: // ... definición de objeto MLNode objMLNode = ParseNode(objMLAttribute.Name, objTokenizer, false); // Añade el nodo como objeto objMLNodeParent.Nodes.Add(objMLNode); break; case TokenType.BraceOpen: // ... definición de array objMLNodeParent.Nodes.Add(ParseNodesArray(objMLAttribute.Name, objTokenizer)); break; default: throw new ParserException("Cadena desconocida. " + objActualToken.Lexema); } } // Lee el siguiente token GetNextToken(objTokenizer); // Si es una coma, seguir con el siguiente atributo del nodo, si es una llave de cierre, terminar switch (intIDActualType) { case TokenType.Comma: // ... no hace nada, simplemente pasa a la creación del siguiente nodo break; case TokenType.BracketClose: blnEnd = true; break; default: throw new ParserException("Cadena desconocida. " + objActualToken.Lexema); } } } }
/// <summary> /// Inicializa el objeto de creación de tokens /// </summary> private ParserTokenizer InitTokenizer() { ParserTokenizer objTokenizer = new ParserTokenizer(); // Asigna los tokens objTokenizer.TokensDefinitions.Add(GetTokenDefinition(TokenType.BracketOpen, "{")); objTokenizer.TokensDefinitions.Add(GetTokenDefinition(TokenType.BracketClose, "}")); objTokenizer.TokensDefinitions.Add(GetTokenDefinition(TokenType.String, "\"", "\"")); objTokenizer.TokensDefinitions.Add(GetTokenDefinition(TokenType.Colon, ":")); objTokenizer.TokensDefinitions.Add(GetTokenDefinition(TokenType.Comma, ",")); objTokenizer.TokensDefinitions.Add(GetTokenDefinition(TokenType.BraceOpen, "[")); objTokenizer.TokensDefinitions.Add(GetTokenDefinition(TokenType.BraceClose, "]")); objTokenizer.TokensDefinitions.Add(GetTokenDefinition(TokenType.True, "true")); objTokenizer.TokensDefinitions.Add(GetTokenDefinition(TokenType.False, "false")); objTokenizer.TokensDefinitions.Add(GetTokenDefinition(TokenType.Null, "null")); objTokenizer.TokensDefinitions.Add((int) TokenType.Numeric, "Numeric"); // Devuelve el objeto de creación de tokens return objTokenizer; }
/// <summary> /// Obtiene los datos del siguiente token /// </summary> private void GetNextToken(ParserTokenizer objTokenizer) { objActualToken = objTokenizer.GetToken(); intIDActualType = GetIDType(objActualToken); }
/// <summary> /// Interpreta los nodos de un array /// </summary> private MLNode ParseNodesArray(string strNodeParent, ParserTokenizer objTokenizer) { MLNode objMLNode = new MLNode(strNodeParent); bool blnEnd = false; int intIndex = 0; // Obtiene el siguiente token (puede que se trate de un array vacío) while (!objTokenizer.IsEof() && !blnEnd) { // Obtiene el siguiente token GetNextToken(objTokenizer); // Interpreta el nodo switch (intIDActualType) { case TokenType.BracketOpen: objMLNode.Nodes.Add(ParseNode("Struct", objTokenizer, false)); break; case TokenType.BraceOpen: objMLNode.Nodes.Add(ParseNodesArray(objTokenizer)); break; case TokenType.String: case TokenType.Numeric: case TokenType.True: case TokenType.False: case TokenType.Null: objMLNode.Nodes.Add("Item", objActualToken.Lexema); break; case TokenType.Comma: // ... no hace nada, simplemente pasa al siguiente incrementando el índice intIndex++; break; case TokenType.BraceClose: // ... corchete de cierre, indica que ha terminado blnEnd = true; break; default: throw new NotImplementedException("No se ha encontrado un token válido ('" + objActualToken.Lexema + "')"); } } // Si no se ha encontrado un corchete, lanza una excepción if (!blnEnd) throw new ParserException("No se ha encontrado el carácter de fin del array ']'"); // Devuelve la colección de nodos return objMLNode; }
/// <summary> /// Interpreta los nodos de un array /// </summary> private MLNode ParseNodesArray(ParserTokenizer objTokenizer) { return ParseNodesArray("Array", objTokenizer); }