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
16namespace 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