1 | // Copyright 2009-2021 Intel Corporation |
2 | // SPDX-License-Identifier: Apache-2.0 |
3 | |
4 | #pragma once |
5 | |
6 | #include "../sys/platform.h" |
7 | #include "../sys/ref.h" |
8 | #include "../sys/filename.h" |
9 | #include "../sys/string.h" |
10 | |
11 | #include <vector> |
12 | #include <iostream> |
13 | #include <cstdio> |
14 | #include <string.h> |
15 | |
16 | namespace embree |
17 | { |
18 | /*! stores the location of a stream element in the source */ |
19 | class ParseLocation |
20 | { |
21 | public: |
22 | ParseLocation () : lineNumber(-1), colNumber(-1) {} |
23 | ParseLocation (std::shared_ptr<std::string> fileName, ssize_t lineNumber, ssize_t colNumber, ssize_t /*charNumber*/) |
24 | : fileName(fileName), lineNumber(lineNumber), colNumber(colNumber) {} |
25 | |
26 | std::string str() const |
27 | { |
28 | std::string str = "unknown" ; |
29 | if (fileName) str = *fileName; |
30 | if (lineNumber >= 0) str += " line " + toString(lineNumber); |
31 | if (lineNumber >= 0 && colNumber >= 0) str += " character " + toString(colNumber); |
32 | return str; |
33 | } |
34 | |
35 | private: |
36 | std::shared_ptr<std::string> fileName; /// name of the file (or stream) the token is from |
37 | ssize_t lineNumber; /// the line number the token is from |
38 | ssize_t colNumber; /// the character number in the current line |
39 | }; |
40 | |
41 | /*! a stream class templated over the stream elements */ |
42 | template<typename T> class Stream : public RefCount |
43 | { |
44 | enum { BUF_SIZE = 1024 }; |
45 | |
46 | private: |
47 | virtual T next() = 0; |
48 | virtual ParseLocation location() = 0; |
49 | __forceinline std::pair<T,ParseLocation> nextHelper() { |
50 | ParseLocation l = location(); |
51 | T v = next(); |
52 | return std::pair<T,ParseLocation>(v,l); |
53 | } |
54 | __forceinline void push_back(const std::pair<T,ParseLocation>& v) { |
55 | if (past+future == BUF_SIZE) pop_front(); |
56 | size_t end = (start+past+future++)%BUF_SIZE; |
57 | buffer[end] = v; |
58 | } |
59 | __forceinline void pop_front() { |
60 | if (past == 0) THROW_RUNTIME_ERROR("stream buffer empty" ); |
61 | start = (start+1)%BUF_SIZE; past--; |
62 | } |
63 | public: |
64 | Stream () : start(0), past(0), future(0), buffer(BUF_SIZE) {} |
65 | virtual ~Stream() {} |
66 | |
67 | public: |
68 | |
69 | const ParseLocation& loc() { |
70 | if (future == 0) push_back(nextHelper()); |
71 | return buffer[(start+past)%BUF_SIZE].second; |
72 | } |
73 | T get() { |
74 | if (future == 0) push_back(nextHelper()); |
75 | T t = buffer[(start+past)%BUF_SIZE].first; |
76 | past++; future--; |
77 | return t; |
78 | } |
79 | const T& peek() { |
80 | if (future == 0) push_back(nextHelper()); |
81 | return buffer[(start+past)%BUF_SIZE].first; |
82 | } |
83 | const T& unget(size_t n = 1) { |
84 | if (past < n) THROW_RUNTIME_ERROR ("cannot unget that many items" ); |
85 | past -= n; future += n; |
86 | return peek(); |
87 | } |
88 | void drop() { |
89 | if (future == 0) push_back(nextHelper()); |
90 | past++; future--; |
91 | } |
92 | private: |
93 | size_t start,past,future; |
94 | std::vector<std::pair<T,ParseLocation> > buffer; |
95 | }; |
96 | |
97 | /*! warps an iostream stream */ |
98 | class StdStream : public Stream<int> |
99 | { |
100 | public: |
101 | StdStream (std::istream& cin, const std::string& name = "std::stream" ) |
102 | : cin(cin), lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name))) {} |
103 | ~StdStream() {} |
104 | ParseLocation location() { |
105 | return ParseLocation(name,lineNumber,colNumber,charNumber); |
106 | } |
107 | int next() { |
108 | int c = cin.get(); |
109 | if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++; |
110 | charNumber++; |
111 | return c; |
112 | } |
113 | private: |
114 | std::istream& cin; |
115 | ssize_t lineNumber; /// the line number the token is from |
116 | ssize_t colNumber; /// the character number in the current line |
117 | ssize_t charNumber; /// the character in the file |
118 | std::shared_ptr<std::string> name; /// name of buffer |
119 | }; |
120 | |
121 | /*! creates a stream from a file */ |
122 | class FileStream : public Stream<int> |
123 | { |
124 | public: |
125 | |
126 | FileStream (FILE* file, const std::string& name = "file" ) |
127 | : file(file), lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name))) {} |
128 | |
129 | FileStream (const FileName& fileName) |
130 | : lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(fileName.str()))) |
131 | { |
132 | file = fopen(fileName.c_str(),"r" ); |
133 | if (file == nullptr) THROW_RUNTIME_ERROR("cannot open file " + fileName.str()); |
134 | } |
135 | ~FileStream() { if (file) fclose(file); } |
136 | |
137 | public: |
138 | ParseLocation location() { |
139 | return ParseLocation(name,lineNumber,colNumber,charNumber); |
140 | } |
141 | |
142 | int next() { |
143 | int c = fgetc(file); |
144 | if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++; |
145 | charNumber++; |
146 | return c; |
147 | } |
148 | |
149 | private: |
150 | FILE* file; |
151 | ssize_t lineNumber; /// the line number the token is from |
152 | ssize_t colNumber; /// the character number in the current line |
153 | ssize_t charNumber; /// the character in the file |
154 | std::shared_ptr<std::string> name; /// name of buffer |
155 | }; |
156 | |
157 | /*! creates a stream from a string */ |
158 | class StrStream : public Stream<int> |
159 | { |
160 | public: |
161 | |
162 | StrStream (const char* str) |
163 | : str(str), lineNumber(1), colNumber(0), charNumber(0) {} |
164 | |
165 | public: |
166 | ParseLocation location() { |
167 | return ParseLocation(std::shared_ptr<std::string>(),lineNumber,colNumber,charNumber); |
168 | } |
169 | |
170 | int next() { |
171 | int c = str[charNumber]; |
172 | if (c == 0) return EOF; |
173 | if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++; |
174 | charNumber++; |
175 | return c; |
176 | } |
177 | |
178 | private: |
179 | const char* str; |
180 | ssize_t lineNumber; /// the line number the token is from |
181 | ssize_t colNumber; /// the character number in the current line |
182 | ssize_t charNumber; /// the character in the file |
183 | }; |
184 | |
185 | /*! creates a character stream from a command line */ |
186 | class CommandLineStream : public Stream<int> |
187 | { |
188 | public: |
189 | CommandLineStream (int argc, char** argv, const std::string& name = "command line" ) |
190 | : i(0), j(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name))) |
191 | { |
192 | if (argc > 0) { |
193 | for (size_t i=0; argv[0][i] && i<1024; i++) charNumber++; |
194 | charNumber++; |
195 | } |
196 | for (ssize_t k=1; k<argc; k++) args.push_back(argv[k]); |
197 | } |
198 | ~CommandLineStream() {} |
199 | public: |
200 | ParseLocation location() { |
201 | return ParseLocation(name,0,charNumber,charNumber); |
202 | } |
203 | int next() { |
204 | if (i == args.size()) return EOF; |
205 | if (j == args[i].size()) { i++; j=0; charNumber++; return ' '; } |
206 | charNumber++; |
207 | return args[i][j++]; |
208 | } |
209 | private: |
210 | size_t i,j; |
211 | std::vector<std::string> args; |
212 | ssize_t charNumber; /// the character in the file |
213 | std::shared_ptr<std::string> name; /// name of buffer |
214 | }; |
215 | } |
216 | |