protected string ParseDomainName() { StringBuilder builder = new StringBuilder(); do { if (token.Type == TokenType.Identifier) { WordToken wt = token as WordToken; builder.Append(wt.Word); } else if (token.Type == tokenAt) { builder.Append("@"); } else if (token.Type == tokenDot) { builder.Append("."); } GetToken(false); }while (token.Type != TokenType.Whitespace && token.Type != TokenType.EndOfFile && token.Type != TokenType.Numeric && token.Type != tokenControl && !token.IsInList(tokensQueryClass) && !token.IsInList(tokensQueryType)); // skip the rest of the whitespace to have the next token ready GetToken(); return(builder.ToString()); }
// TODO: maintain a list of token types provided by parser so that scanner can remain unbiased // TODO: maintain a list of special token types public Token GetToken() { SkipWhitespace(); if (currType == CharType.Alpha) { WordToken token = WordToken.GetToken(this); // TODO: check for reserved words return(token); } else if (currType == CharType.Numeric) { return(NumberToken.GetToken(this)); } else if (currType == CharType.Quote) { return(StringToken.GetToken(this)); } else if (currType == CharType.EOF) { return(new EndOfFileToken()); } else if (currType == CharType.Special) { SpecialToken token = SpecialToken.GetToken(this); // TODO: check for special token types return(token); } return(null); }
protected override void GetToken() { base.GetToken(); // tokenise special tokens according to this language // multi-character special tokens can also be added by checking scanner.curr for continuation if (token.Type == TokenType.Special) { SpecialToken st = token as SpecialToken; switch (st.Token) { case '=': token.Type = tokenEquals; break; case ';': token.Type = tokenSemicolon; break; case '+': token.Type = tokenPlus; break; case '-': token.Type = tokenMinus; break; case '/': token.Type = tokenDivide; break; case '*': token.Type = tokenMultiply; break; case '(': token.Type = tokenOpenParentheses; break; case ')': token.Type = tokenCloseParentheses; break; } } else if (token.Type == TokenType.Identifier) { // rule out identifiers that are actually reserved words. could be const values like "pi" or logic keywords like "if/then/else/while etc." WordToken wt = token as WordToken; switch (wt.Word) { case "pi": token.Type = tokenPi; break; } } }
// TODO: maintain a list of token types provided by parser so that scanner can remain unbiased // TODO: maintain a list of special token types public Token GetToken(bool skipWhitespace = true) { if (skipWhitespace) { SkipWhitespace(); } if (currType == CharType.Whitespace) { return(new Token() { Type = TokenType.Whitespace }); } else if (currType == CharType.Alpha) { WordToken token = WordToken.GetToken(this); // TODO: check for reserved words return(token); } else if (currType == CharType.Numeric) { // TODO: need a scanner options class that lets me specify things like // skipping whitespace, treating numbers etc. // because here an IP address will be treated as a decimal number // 192.0[.2.1] return(NumberToken.GetToken(this)); } else if (currType == CharType.Quote) { return(StringToken.GetToken(this)); } else if (currType == CharType.EOF) { return(new EndOfFileToken()); } else if (currType == CharType.Special) { SpecialToken token = SpecialToken.GetToken(this); // TODO: check for special token types return(token); } return(null); }
protected override void ParseFactor() { if (token.Type == TokenType.Identifier) { WordToken wt = token as WordToken; var node = SearchAll(wt.Word); if (node == null) { throw new InvalidOperationException("Unknown identifier"); } else { runtimeStack.Push(node.Value); } GetToken(); } else if (token.Type == tokenPi) { runtimeStack.Push(Math.PI); GetToken(); } else if (token.Type == TokenType.Numeric) { NumberToken nt = token as NumberToken; runtimeStack.Push(nt.Value); GetToken(); } else if (token.Type == tokenOpenParentheses) { GetToken(); ParseExpression(); if (token.Type == tokenCloseParentheses) { GetToken(); } else { throw new InvalidOperationException("No closing parentheses"); } } }
public Token Get() { int tokenCode = -1; do { tokenCode = code[index++]; if (tokenCode == TokenType.LineMarker) { // TODO: replicate the global currentLineNumber from book int lineNumber = code[index++]; } }while (tokenCode == TokenType.LineMarker); if (tokenCode == TokenType.Numeric) { var token = new NumberToken(); var node = GetSymbolTableNode(); token.Value = node.Value; return(token); } if (tokenCode == TokenType.String) { var token = new StringToken(); var node = GetSymbolTableNode(); token.Value = node.Symbol; return(token); } if (tokenCode == TokenType.Identifier) { var token = new WordToken(); var node = GetSymbolTableNode(); token.Word = node.Symbol; return(token); } var defaultToken = new WordToken(); defaultToken.Word = ""; return(defaultToken); }
public static WordToken GetToken(Scanner scanner) { WordToken t = new WordToken(); t.sc = scanner.col; t.sr = scanner.row; StringBuilder sb = new StringBuilder(); while (scanner.currType == CharType.Alpha || scanner.currType == CharType.Numeric) { sb.Append(scanner.curr); scanner.Next(); } t.Word = sb.ToString(); t.ec = scanner.col; t.er = scanner.row; t.Type = TokenType.Identifier; return(t); }
protected override void ParseAssignment() { WordToken identifier = token as WordToken; var node = SearchAll(identifier.Word); if (node == null) { node = EnterLocal(identifier.Word); } GetToken(); if (token.Type == tokenEquals) { GetToken(); ParseExpression(); node.Value = runtimeStack.Pop(); } }
protected override void GetToken(bool skipWhitespace = true) { base.GetToken(skipWhitespace); if (token.Type == TokenType.Special) { SpecialToken st = token as SpecialToken; if (st.Token == ';') { // we don't care about comments, keep scanning and return a real token token.Type = tokenSemicolon; do { scanner.Next(); }while (scanner.curr != '\n'); scanner.Next(); GetToken(skipWhitespace); } else if (st.Token == '$') { token.Type = tokenControl; } else if (st.Token == '(') { // TODO: I think don't ignore these, but i need to know when they will come // so far SOA and WKS records, but if they could come anywhere then // i need to cater for that // WKS is particularly problematic because it isn't fixed length fields //token.Type = tokenOpenParentheses; // i think just ignore parentheses GetToken(skipWhitespace); } else if (st.Token == ')') { // token.Type = tokenCloseParentheses; GetToken(skipWhitespace); } else if (st.Token == '.') { token.Type = tokenDot; } else if (st.Token == ':') { token.Type = tokenColon; } else if (st.Token == '@') { token.Type = tokenAt; } } else if (token.Type == TokenType.Identifier) { WordToken wt = token as WordToken; if (wt.Word == "INCLUDE") { token.Type = tokenInclude; } else if (wt.Word == "ORIGIN") { token.Type = tokenOrigin; } else if (wt.Word == "TTL") { token.Type = tokenTTL; } else if (wt.Word == "IN") { token.Type = tokenInternet; } else if (wt.Word == "CS") { token.Type = tokenCSNET; } else if (wt.Word == "CH") { token.Type = tokenChaos; } else if (wt.Word == "HS") { token.Type = tokenHesiod; } else if (wt.Word == "AFXR") { token.Type = tokenTransfer; } else if (wt.Word == "MAILB") { token.Type = tokenMailbox; } else if (wt.Word == "MAILA") { token.Type = tokenMailAgent; } else if (wt.Word == "A") { token.Type = tokenHostAddress; } else if (wt.Word == "AAAA") { token.Type = tokenHostIPv6Address; } else if (wt.Word == "NS") { token.Type = tokenNameServer; } else if (wt.Word == "MD") { token.Type = tokenMailDestination; } else if (wt.Word == "MF") { token.Type = tokenMailForwarder; } else if (wt.Word == "CNAME") { token.Type = tokenCanonicalName; } else if (wt.Word == "SOA") { token.Type = tokenAuthority; } else if (wt.Word == "WKS") { token.Type = tokenWellKnownService; } else if (wt.Word == "PTR") { token.Type = tokenPointer; } else if (wt.Word == "HINFO") { token.Type = tokenHostInfo; } else if (wt.Word == "MINFO") { token.Type = tokenMailboxInfo; } else if (wt.Word == "MX") { token.Type = tokenMailExchange; } else if (wt.Word == "TXT") { token.Type = tokenText; } } }
protected void ParseResourceRecord() { bool haveType = false; MasterFileEntry entry = new MasterFileEntry(); while (haveType == false && token.Type != TokenType.EndOfFile) { if (token.Type == TokenType.Numeric) { // most likely a <rr> beginning with TTL // [<TTL>] [<class>] <type> <RDATA> NumberToken nt = token as NumberToken; entry.TTL = (int)nt.Value; GetToken(); } else if (token.IsInList(tokensQueryClass)) { // most likely a <rr> beginning with class // [<class>] [<TTL>] <type> <RDATA> WordToken wt = token as WordToken; entry.Class = wt.Word; GetToken(); } else if (token.IsInList(tokensQueryType)) { haveType = true; WordToken wt = token as WordToken; entry.Type = wt.Word; // prepare to parse the data if (token.Type == tokenCanonicalName) { // name string - probably fqdn GetToken(); entry.Data = ParseDomainName(); } else if (token.Type == tokenHostInfo) { // CPU string GetToken(); // OS string GetToken(); GetToken(); } else if (token.Type == tokenMailExchange) { GetToken(); NumberToken nt = token as NumberToken; entry.Priority = (int)nt.Value; GetToken(); entry.Data = ParseDomainName(); } else if (token.Type == tokenNameServer) { GetToken(); entry.Data = ParseDomainName(); } else if (token.Type == tokenPointer) { GetToken(); entry.Data = ParseDomainName(); } else if (token.Type == tokenAuthority) { // name server GetToken(); // TODO: if token is open parentheses then loop until close parentheses (and stop scanner from swallowing parentheses) entry.NameServer = ParseDomainName(); // mailbox of responsible person entry.Responsible = ParseDomainName(); // serial number NumberToken nt = token as NumberToken; entry.SerialNumber = (int)nt.Value; // refresh interval GetToken(); nt = token as NumberToken; entry.RefreshInterval = (int)nt.Value; // retry interval GetToken(); nt = token as NumberToken; entry.RetryInterval = (int)nt.Value; // expiry timeout GetToken(); nt = token as NumberToken; entry.ExpiryTimeout = (int)nt.Value; // minimum ttl GetToken(); nt = token as NumberToken; entry.MinimumTTL = (int)nt.Value; GetToken(); } else if (token.Type == tokenText) { GetToken(); // TODO: this is wrong and probably needs additional parsing entry.Data = ((WordToken)token).Word; GetToken(); } else if (token.Type == tokenHostAddress) { GetToken(); entry.Data = ParseIPv4Address(); } else if (token.Type == tokenHostIPv6Address) { GetToken(); entry.Data = ParseIPv6Address(); } else if (token.Type == tokenWellKnownService) { // address GetToken(); string address = ParseIPv4Address(); string protocol = ((WordToken)token).Word; // TODO: open parentheses, loop until close } } else { // most likely a <rr> beginning with <owner> // <domain-name> [<class>] [<TTL>] <type> <RDATA> entry.Owner = ParseDomainName(); if (entry.Owner != "@") { // set default owner in case we reach another record that doesn't have an owner // see section 5.1 owner = entry.Owner; } } } if (entry.Owner == null) { entry.Owner = owner; } if (entry.Owner == "@") { entry.Owner = origin; } else if (entry.Owner.EndsWith(".") == false) { entry.Owner += "." + origin; } // add to the running list of entries found Entries.Add(entry); Console.WriteLine($"Parsed resource record: {entry.Owner}\t{entry.Type}\t{entry.Class}\t{entry.Data}"); }