1 |
tim |
770 |
/* ANTLR Translator Generator |
2 |
|
|
* Project led by Terence Parr at http://www.jGuru.com |
3 |
|
|
* Software rights: http://www.antlr.org/license.html |
4 |
|
|
* |
5 |
|
|
* $Id: ANTLRUtil.cpp,v 1.1 2005-12-02 15:38:02 tim Exp $ |
6 |
|
|
*/ |
7 |
|
|
|
8 |
|
|
#include <antlr/config.hpp> |
9 |
|
|
#include <antlr/IOException.hpp> |
10 |
|
|
|
11 |
|
|
#include <iostream> |
12 |
|
|
#include <cctype> |
13 |
|
|
#include <string> |
14 |
|
|
|
15 |
|
|
#ifdef ANTLR_CXX_SUPPORTS_NAMESPACE |
16 |
|
|
namespace antlr { |
17 |
|
|
#endif |
18 |
|
|
|
19 |
|
|
/** Eat whitespace from the input stream |
20 |
|
|
* @param is the stream to read from |
21 |
|
|
*/ |
22 |
|
|
ANTLR_USE_NAMESPACE(std)istream& eatwhite( ANTLR_USE_NAMESPACE(std)istream& is ) |
23 |
|
|
{ |
24 |
|
|
char c; |
25 |
|
|
while( is.get(c) ) |
26 |
|
|
{ |
27 |
|
|
#ifdef ANTLR_CCTYPE_NEEDS_STD |
28 |
|
|
if( !ANTLR_USE_NAMESPACE(std)isspace(c) ) |
29 |
|
|
#else |
30 |
|
|
if( !isspace(c) ) |
31 |
|
|
#endif |
32 |
|
|
{ |
33 |
|
|
is.putback(c); |
34 |
|
|
break; |
35 |
|
|
} |
36 |
|
|
} |
37 |
|
|
return is; |
38 |
|
|
} |
39 |
|
|
|
40 |
|
|
/** Read a string enclosed by '"' from a stream. Also handles escaping of \". |
41 |
|
|
* Skips leading whitespace. |
42 |
|
|
* @param in the istream to read from. |
43 |
|
|
* @returns the string read from file exclusive the '"' |
44 |
|
|
* @throws IOException if string is badly formatted |
45 |
|
|
*/ |
46 |
|
|
ANTLR_USE_NAMESPACE(std)string read_string( ANTLR_USE_NAMESPACE(std)istream& in ) |
47 |
|
|
{ |
48 |
|
|
char ch; |
49 |
|
|
ANTLR_USE_NAMESPACE(std)string ret(""); |
50 |
|
|
// States for a simple state machine... |
51 |
|
|
enum { START, READING, ESCAPE, FINISHED }; |
52 |
|
|
int state = START; |
53 |
|
|
|
54 |
|
|
eatwhite(in); |
55 |
|
|
|
56 |
|
|
while( state != FINISHED && in.get(ch) ) |
57 |
|
|
{ |
58 |
|
|
switch( state ) |
59 |
|
|
{ |
60 |
|
|
case START: |
61 |
|
|
// start state: check wether starting with " then switch to READING |
62 |
|
|
if( ch != '"' ) |
63 |
|
|
throw IOException("string must start with '\"'"); |
64 |
|
|
state = READING; |
65 |
|
|
continue; |
66 |
|
|
case READING: |
67 |
|
|
// reading state: look out for escape sequences and closing " |
68 |
|
|
if( ch == '\\' ) // got escape sequence |
69 |
|
|
{ |
70 |
|
|
state = ESCAPE; |
71 |
|
|
continue; |
72 |
|
|
} |
73 |
|
|
if( ch == '"' ) // close quote -> stop |
74 |
|
|
{ |
75 |
|
|
state = FINISHED; |
76 |
|
|
continue; |
77 |
|
|
} |
78 |
|
|
ret += ch; // else append... |
79 |
|
|
continue; |
80 |
|
|
case ESCAPE: |
81 |
|
|
switch(ch) |
82 |
|
|
{ |
83 |
|
|
case '\\': |
84 |
|
|
ret += ch; |
85 |
|
|
state = READING; |
86 |
|
|
continue; |
87 |
|
|
case '"': |
88 |
|
|
ret += ch; |
89 |
|
|
state = READING; |
90 |
|
|
continue; |
91 |
|
|
case '0': |
92 |
|
|
ret += '\0'; |
93 |
|
|
state = READING; |
94 |
|
|
continue; |
95 |
|
|
default: // unrecognized escape is not mapped |
96 |
|
|
ret += '\\'; |
97 |
|
|
ret += ch; |
98 |
|
|
state = READING; |
99 |
|
|
continue; |
100 |
|
|
} |
101 |
|
|
} |
102 |
|
|
} |
103 |
|
|
if( state != FINISHED ) |
104 |
|
|
throw IOException("badly formatted string: "+ret); |
105 |
|
|
|
106 |
|
|
return ret; |
107 |
|
|
} |
108 |
|
|
|
109 |
|
|
/* Read a ([A-Z][0-9][a-z]_)* kindoff thing. Skips leading whitespace. |
110 |
|
|
* @param in the istream to read from. |
111 |
|
|
*/ |
112 |
|
|
ANTLR_USE_NAMESPACE(std)string read_identifier( ANTLR_USE_NAMESPACE(std)istream& in ) |
113 |
|
|
{ |
114 |
|
|
char ch; |
115 |
|
|
ANTLR_USE_NAMESPACE(std)string ret(""); |
116 |
|
|
|
117 |
|
|
eatwhite(in); |
118 |
|
|
|
119 |
|
|
while( in.get(ch) ) |
120 |
|
|
{ |
121 |
|
|
#ifdef ANTLR_CCTYPE_NEEDS_STD |
122 |
|
|
if( ANTLR_USE_NAMESPACE(std)isupper(ch) || |
123 |
|
|
ANTLR_USE_NAMESPACE(std)islower(ch) || |
124 |
|
|
ANTLR_USE_NAMESPACE(std)isdigit(ch) || |
125 |
|
|
ch == '_' ) |
126 |
|
|
#else |
127 |
|
|
if( isupper(ch) || islower(ch) || isdigit(ch) || ch == '_' ) |
128 |
|
|
#endif |
129 |
|
|
ret += ch; |
130 |
|
|
else |
131 |
|
|
{ |
132 |
|
|
in.putback(ch); |
133 |
|
|
break; |
134 |
|
|
} |
135 |
|
|
} |
136 |
|
|
return ret; |
137 |
|
|
} |
138 |
|
|
|
139 |
|
|
/** Read a attribute="value" thing. Leading whitespace is skipped. |
140 |
|
|
* Between attribute and '=' no whitespace is allowed. After the '=' it is |
141 |
|
|
* permitted. |
142 |
|
|
* @param in the istream to read from. |
143 |
|
|
* @param attribute string the attribute name is put in |
144 |
|
|
* @param value string the value of the attribute is put in |
145 |
|
|
* @throws IOException if something is fishy. E.g. malformed quoting |
146 |
|
|
* or missing '=' |
147 |
|
|
*/ |
148 |
|
|
void read_AttributeNValue( ANTLR_USE_NAMESPACE(std)istream& in, |
149 |
|
|
ANTLR_USE_NAMESPACE(std)string& attribute, |
150 |
|
|
ANTLR_USE_NAMESPACE(std)string& value ) |
151 |
|
|
{ |
152 |
|
|
attribute = read_identifier(in); |
153 |
|
|
|
154 |
|
|
char ch; |
155 |
|
|
if( in.get(ch) && ch == '=' ) |
156 |
|
|
value = read_string(in); |
157 |
|
|
else |
158 |
|
|
throw IOException("invalid attribute=value thing "+attribute); |
159 |
|
|
} |
160 |
|
|
|
161 |
|
|
#ifdef ANTLR_CXX_SUPPORTS_NAMESPACE |
162 |
|
|
} |
163 |
|
|
#endif |