5
// Aaron Bockover <abockover@novell.com>
7
// Copyright (C) 2007-2008 Novell, Inc.
9
// Permission is hereby granted, free of charge, to any person obtaining
10
// a copy of this software and associated documentation files (the
11
// "Software"), to deal in the Software without restriction, including
12
// without limitation the rights to use, copy, modify, merge, publish,
13
// distribute, sublicense, and/or sell copies of the Software, and to
14
// permit persons to whom the Software is furnished to do so, subject to
15
// the following conditions:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32
using System.Text.RegularExpressions;
33
using System.Globalization;
35
namespace Hyena.SExpEngine
37
public class ParserException : ApplicationException
39
public ParserException(string token, int line, int col, Exception inner) : base(String.Format(
40
"Parser exception at token `{0}' [{1},{2}]: {3}",
41
token, line, col, inner == null ? "Unknown error" : inner.Message), inner)
48
private static Regex number_regex = new Regex(@"^[-+]?(0x[\dA-Fa-f]+)?[\d]*\.?[\d]*([eE][-+]?[\d]+)?$");
49
private static System.Globalization.CultureInfo culture_info = new System.Globalization.CultureInfo("en-US");
51
private StreamReader reader;
54
private StringBuilder current_token;
55
private TreeNode root_node ;
56
private TreeNode current_parent;
65
public TreeNode Parse(string input)
67
return Parse(new MemoryStream(Encoding.UTF8.GetBytes(input)));
70
public TreeNode Parse(Stream stream)
72
return Parse(new StreamReader(stream));
75
public TreeNode Parse(StreamReader reader)
79
current_token = new StringBuilder();
80
root_node = new TreeNode();
81
current_parent = root_node;
90
throw new ApplicationException("Scope does pop back to zero");
92
} catch(Exception e) {
93
throw new ParserException(current_token.ToString(), line, column, e);
99
private void Tokenize()
101
bool in_string = false;
102
bool in_comment = false;
105
int ich = reader.Read();
120
if(ch == '\r' || ch == '\n') {
139
current_token.Append(ch);
151
if((char)reader.Peek() == '"') {
152
current_token.Append((char)reader.Read());
157
current_token.Append(ch);
164
if(Char.IsWhiteSpace(ch)) {
166
current_token.Append(ch);
171
current_token.Append(ch);
182
private void ScopePush()
184
current_parent = new TreeNode(current_parent);
188
private void ScopePop()
190
current_parent = current_parent.Parent;
194
private void TokenPush(bool as_string)
196
if(current_token.Length == 0 && !as_string) {
200
TreeNode node = null;
201
string token = current_token.ToString();
204
Console.Write("{3}[{0}] TOKEN({4},{5}): [{2}{1}{2}]", scope, token,
205
as_string ? "\"" : String.Empty, String.Empty.PadLeft(scope - 1, ' '),
206
line, column - current_token.Length);
210
node = new StringLiteral(token);
211
} else if(token == "#t") {
212
node = new BooleanLiteral(true);
213
} else if(token == "#f") {
214
node = new BooleanLiteral(false);
215
} else if(token.Length > 0 && token != "." && token != "-" &&
216
token != "+" && number_regex.IsMatch(token)) {
218
if(token.StartsWith("0x") || token.StartsWith("-0x")) {
219
int offset = token[0] == '-' ? 3 : 2;
220
int value = Int32.Parse(token.Substring(offset),
221
NumberStyles.HexNumber, culture_info.NumberFormat);
222
node = new IntLiteral(value * (offset == 3 ? -1 : 1));
223
} else if(token.Contains(".")) {
224
node = new DoubleLiteral(Double.Parse(token,
225
NumberStyles.Float, culture_info.NumberFormat));
227
node = new IntLiteral(Int32.Parse(token,
228
NumberStyles.Integer, culture_info.NumberFormat));
231
throw new FormatException("Invalid number format: " + token);
234
node = new FunctionNode(token);
238
Console.WriteLine(" => [{0}]", node);
242
node.Column = column;
243
current_parent.AddChild(node);
245
current_token.Remove(0, current_token.Length);
249
get { return debug; }
250
set { debug = value; }