using System; using System.Collections.Generic; namespace ImaginationOverflow.UniversalDeepLinking.Editor.Xcode.PBX { class ValueAST {} // IdentifierAST := \ class IdentifierAST : ValueAST { public int value = 0; // token id } // TreeAST := '{' KeyValuePairList '}' // KeyValuePairList := KeyValuePair ',' KeyValuePairList // KeyValuePair ',' // (empty) class TreeAST : ValueAST { public List values = new List(); } // ListAST := '(' ValueList ')' // ValueList := ValueAST ',' ValueList // ValueAST ',' // (empty) class ArrayAST : ValueAST { public List values = new List(); } // KeyValueAST := IdentifierAST '=' ValueAST ';' // ValueAST := IdentifierAST | TreeAST | ListAST class KeyValueAST { public IdentifierAST key = null; public ValueAST value = null; // either IdentifierAST, TreeAST or ListAST } class Parser { TokenList tokens; int currPos; public Parser(TokenList tokens) { this.tokens = tokens; currPos = SkipComments(0); } int SkipComments(int pos) { while (pos < tokens.Count && tokens[pos].type == TokenType.Comment) { pos++; } return pos; } // returns new position int IncInternal(int pos) { if (pos >= tokens.Count) return pos; pos++; return SkipComments(pos); } // Increments current pointer if not past the end, returns previous pos int Inc() { int prev = currPos; currPos = IncInternal(currPos); return prev; } // Returns the token type of the current token TokenType Tok() { if (currPos >= tokens.Count) return TokenType.EOF; return tokens[currPos].type; } void SkipIf(TokenType type) { if (Tok() == type) Inc(); } string GetErrorMsg() { return "Invalid PBX project (parsing line " + tokens[currPos].line + ")"; } public IdentifierAST ParseIdentifier() { if (Tok() != TokenType.String && Tok() != TokenType.QuotedString) throw new Exception(GetErrorMsg()); var ast = new IdentifierAST(); ast.value = Inc(); return ast; } public TreeAST ParseTree() { if (Tok() != TokenType.LBrace) throw new Exception(GetErrorMsg()); Inc(); var ast = new TreeAST(); while (Tok() != TokenType.RBrace && Tok() != TokenType.EOF) { ast.values.Add(ParseKeyValue()); } SkipIf(TokenType.RBrace); return ast; } public ArrayAST ParseList() { if (Tok() != TokenType.LParen) throw new Exception(GetErrorMsg()); Inc(); var ast = new ArrayAST(); while (Tok() != TokenType.RParen && Tok() != TokenType.EOF) { ast.values.Add(ParseValue()); SkipIf(TokenType.Comma); } SkipIf(TokenType.RParen); return ast; } // throws on error public KeyValueAST ParseKeyValue() { var ast = new KeyValueAST(); ast.key = ParseIdentifier(); if (Tok() != TokenType.Eq) throw new Exception(GetErrorMsg()); Inc(); // skip '=' ast.value = ParseValue(); SkipIf(TokenType.Semicolon); return ast; } // throws on error public ValueAST ParseValue() { if (Tok() == TokenType.String || Tok() == TokenType.QuotedString) return ParseIdentifier(); else if (Tok() == TokenType.LBrace) return ParseTree(); else if (Tok() == TokenType.LParen) return ParseList(); throw new Exception(GetErrorMsg()); } } } // namespace UnityModule.iOS.Xcode