1 | /* 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:$ |
---|
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 |
---|