root/lang/csharp/IrcSendOnly/syntax.cs

Revision 831, 8.5 kB (checked in by gyuque, 15 months ago)

lang/csharp/IrcSendOnly

Line 
1/*=====================================================================
2  This file is part of the Microsoft Live Communications Code Samples.
3
4  Copyright (C) 2005, 2006 Microsoft Corporation.  All rights reserved.
5
6This source code is intended only as a supplement to Microsoft
7Development Tools and/or on-line documentation.  See these other
8materials for detailed information regarding Microsoft code samples.
9
10THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
11KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
13PARTICULAR PURPOSE.
14=====================================================================*/
15
16using System;
17using System.Collections;
18using System.Globalization;
19using System.IO;
20using System.Text;
21using System.Text.RegularExpressions;
22
23namespace JsonApi
24{
25    internal class Undefined { }
26
27    public class Parser
28    {
29        private Token token;
30
31        private ArrayList parse_array()
32        {
33            ArrayList array = new ArrayList();
34            Token original = token;
35
36            token = token.Next;
37            if (token.Type != Token.Types.Symbol || token.Value != "[")
38            {
39                token = original;
40                return null;
41            }
42            while (true)
43            {
44                object value = parse_value();
45
46                token = token.Next;
47                if (value == null)
48                {
49                    break;
50                }
51
52                array.Add(value is Undefined ? null : value);
53
54                if (token.Type != Token.Types.Symbol || token.Value != ",")
55                {
56                    break;
57                }
58            }
59            if (token.Type != Token.Types.Symbol || token.Value != "]")
60            {
61                token = original;
62                return null;
63            }
64            return array;
65        }
66
67        private Hashtable parse_object()
68        {
69            Hashtable hashtable = new Hashtable(CaseInsensitiveHashCodeProvider.DefaultInvariant, CaseInsensitiveComparer.DefaultInvariant);
70            Token original = token;
71
72            token = token.Next;
73            if (token.Type != Token.Types.Symbol || token.Value != "{")
74            {
75                token = original;
76                return null;
77            }
78            while (true)
79            {
80                token = token.Next;
81                if (token.Type != Token.Types.Literal)
82                {
83                    break;
84                }
85
86                string key = token.Value;
87
88                token = token.Next;
89                if (token.Type != Token.Types.Symbol || token.Value != ":")
90                {
91                    token = original;
92                    return null;
93                }
94
95                object value = parse_value();
96                if (value == null)
97                {
98                    token = original;
99                    return null;
100                }
101                hashtable[key] = value is Undefined ? null : value;
102
103                token = token.Next;
104                if (token.Type != Token.Types.Symbol || token.Value != ",")
105                {
106                    break;
107                }
108            }
109            if (token.Type != Token.Types.Symbol || token.Value != "}")
110            {
111                token = original;
112                return null;
113            }
114            return hashtable;
115        }
116
117        private object parse_value()
118        {
119            Token original = token;
120            object value;
121
122            token = token.Next;
123            if (token.Type == Token.Types.Keyword)
124            {
125                if (token.Value == "false")
126                {
127                    return false;
128                }
129                else if (token.Value == "null")
130                {
131                    return new Undefined();
132                }
133                else if (token.Value == "true")
134                {
135                    return true;
136                }
137            }
138            else if (token.Type == Token.Types.Literal)
139            {
140                return token.Value;
141            }
142            else if (token.Type == Token.Types.Number)
143            {
144                return double.Parse(token.Value);
145            }
146            token = original;
147            if ((value = parse_object()) != null)
148            {
149                return value;
150            }
151            else if ((value = parse_array()) != null)
152            {
153                return value;
154            }
155            return null;
156        }
157
158        public Parser(string s)
159        {
160            // inject symbol to create dummy token
161            token = new Token(":" + s);
162        }
163
164        public Hashtable Parse()
165        {
166            Hashtable hashtable = parse_object();
167            return token.Type != Token.Types.Error && token.Tail == string.Empty ? hashtable : null;
168        }
169    }
170
171    public class Token
172    {
173        private const string REGEX_ESCAPE = @"\\""|\\/|\\\\|\\b|\\f|\\n|\\r|\\t|\\u(?<unicode>[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])";
174        private const string REGEX_KEYWORD = @"false|null|true";
175        private const string REGEX_NUMBER = @"-?(?:0|[1-9]+)(?:\.[1-9]+)?(?:(?:e|E)(?:-|\+)?[1-9]+)?";
176        private const string REGEX_SYMBOL = @"{|}|:|,|\[|\]";
177
178        private static Regex regex = new Regex(string.Format(@"^\s*(?:(?<keyword>{0})|""(?<literal>(?:[^""\\]|{1})*)""|(?<number>{2})|(?<symbol>{3}))\s*(?<tail>.*)$", REGEX_KEYWORD, REGEX_ESCAPE, REGEX_NUMBER, REGEX_SYMBOL), RegexOptions.Compiled | RegexOptions.Singleline);
179
180        private Types type;
181        private string tail;
182        private string value;
183
184        public enum Types { Error, Keyword, Literal, Number, Symbol };
185
186        static private string OnUnescapeLiteral(Match m)
187        {
188            // check parameter(s)
189            if (m == null)
190            {
191                throw new ArgumentNullException("m");
192            }
193            if (!m.Success)
194            {
195                throw new ArgumentException("invalid Match");
196            }
197
198            switch (m.Value)
199            {
200                case @"\""": return "\"";
201                case @"\/": return "/";
202                case @"\\": return "\\";
203                case @"\b": return "\b";
204                case @"\f": return "\f";
205                case @"\n": return "\n";
206                case @"\r": return "\r";
207                case @"\t": return "\t";
208            }
209
210            Group g = m.Groups["unicode"];
211            return g != null && g.Success
212                ? new string(new char[] { (char)int.Parse(g.Value, NumberStyles.HexNumber) })
213                : string.Empty;
214        }
215
216        public Token Next
217        {
218            get
219            {
220                return type != Types.Error ? new Token(tail) : this;
221            }
222        }
223        public string Tail
224        {
225            get { return tail; }
226        }
227        public Types Type
228        {
229            get { return type; }
230        }
231        public string Value
232        {
233            get { return value; }
234        }
235
236        public Token(string s)
237        {
238            type = Types.Error;
239            tail = s;
240            value = null;
241
242            if (s != null)
243            {
244                Group g;
245                Match m = regex.Match(s);
246
247                if (m.Success)
248                {
249                    if ((g = m.Groups["keyword"]) != null && g.Success)
250                    {
251                        type = Types.Keyword;
252                        value = g.Value;
253                    }
254                    else if ((g = m.Groups["literal"]) != null && g.Success)
255                    {
256                        type = Types.Literal;
257                        value = Regex.Replace(g.Value, REGEX_ESCAPE, new MatchEvaluator(OnUnescapeLiteral));
258                    }
259                    else if ((g = m.Groups["number"]) != null && g.Success)
260                    {
261                        type = Types.Number;
262                        value = g.Value;
263                    }
264                    else if ((g = m.Groups["symbol"]) != null && g.Success)
265                    {
266                        type = Types.Symbol;
267                        value = g.Value;
268                    }
269                    tail = (g = m.Groups["tail"]) != null && g.Success ? g.Value : string.Empty;
270                }
271            }
272        }
273    }
274
275   
276}
Note: See TracBrowser for help on using the browser.