216 lines
6.6 KiB
C++
216 lines
6.6 KiB
C++
|
// Copyright 2009-2020 Intel Corporation
|
||
|
// SPDX-License-Identifier: Apache-2.0
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include "../sys/platform.h"
|
||
|
#include "../sys/ref.h"
|
||
|
#include "../sys/filename.h"
|
||
|
#include "../sys/string.h"
|
||
|
|
||
|
#include <vector>
|
||
|
#include <iostream>
|
||
|
#include <cstdio>
|
||
|
#include <string.h>
|
||
|
|
||
|
namespace embree
|
||
|
{
|
||
|
/*! stores the location of a stream element in the source */
|
||
|
class ParseLocation
|
||
|
{
|
||
|
public:
|
||
|
ParseLocation () : lineNumber(-1), colNumber(-1) {}
|
||
|
ParseLocation (std::shared_ptr<std::string> fileName, ssize_t lineNumber, ssize_t colNumber, ssize_t /*charNumber*/)
|
||
|
: fileName(fileName), lineNumber(lineNumber), colNumber(colNumber) {}
|
||
|
|
||
|
std::string str() const
|
||
|
{
|
||
|
std::string str = "unknown";
|
||
|
if (fileName) str = *fileName;
|
||
|
if (lineNumber >= 0) str += " line " + toString(lineNumber);
|
||
|
if (lineNumber >= 0 && colNumber >= 0) str += " character " + toString(colNumber);
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
std::shared_ptr<std::string> fileName; /// name of the file (or stream) the token is from
|
||
|
ssize_t lineNumber; /// the line number the token is from
|
||
|
ssize_t colNumber; /// the character number in the current line
|
||
|
};
|
||
|
|
||
|
/*! a stream class templated over the stream elements */
|
||
|
template<typename T> class Stream : public RefCount
|
||
|
{
|
||
|
enum { BUF_SIZE = 1024 };
|
||
|
|
||
|
private:
|
||
|
virtual T next() = 0;
|
||
|
virtual ParseLocation location() = 0;
|
||
|
__forceinline std::pair<T,ParseLocation> nextHelper() {
|
||
|
ParseLocation l = location();
|
||
|
T v = next();
|
||
|
return std::pair<T,ParseLocation>(v,l);
|
||
|
}
|
||
|
__forceinline void push_back(const std::pair<T,ParseLocation>& v) {
|
||
|
if (past+future == BUF_SIZE) pop_front();
|
||
|
size_t end = (start+past+future++)%BUF_SIZE;
|
||
|
buffer[end] = v;
|
||
|
}
|
||
|
__forceinline void pop_front() {
|
||
|
if (past == 0) THROW_RUNTIME_ERROR("stream buffer empty");
|
||
|
start = (start+1)%BUF_SIZE; past--;
|
||
|
}
|
||
|
public:
|
||
|
Stream () : start(0), past(0), future(0), buffer(BUF_SIZE) {}
|
||
|
virtual ~Stream() {}
|
||
|
|
||
|
public:
|
||
|
|
||
|
const ParseLocation& loc() {
|
||
|
if (future == 0) push_back(nextHelper());
|
||
|
return buffer[(start+past)%BUF_SIZE].second;
|
||
|
}
|
||
|
T get() {
|
||
|
if (future == 0) push_back(nextHelper());
|
||
|
T t = buffer[(start+past)%BUF_SIZE].first;
|
||
|
past++; future--;
|
||
|
return t;
|
||
|
}
|
||
|
const T& peek() {
|
||
|
if (future == 0) push_back(nextHelper());
|
||
|
return buffer[(start+past)%BUF_SIZE].first;
|
||
|
}
|
||
|
const T& unget(size_t n = 1) {
|
||
|
if (past < n) THROW_RUNTIME_ERROR ("cannot unget that many items");
|
||
|
past -= n; future += n;
|
||
|
return peek();
|
||
|
}
|
||
|
void drop() {
|
||
|
if (future == 0) push_back(nextHelper());
|
||
|
past++; future--;
|
||
|
}
|
||
|
private:
|
||
|
size_t start,past,future;
|
||
|
std::vector<std::pair<T,ParseLocation> > buffer;
|
||
|
};
|
||
|
|
||
|
/*! warps an iostream stream */
|
||
|
class StdStream : public Stream<int>
|
||
|
{
|
||
|
public:
|
||
|
StdStream (std::istream& cin, const std::string& name = "std::stream")
|
||
|
: cin(cin), lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name))) {}
|
||
|
~StdStream() {}
|
||
|
ParseLocation location() {
|
||
|
return ParseLocation(name,lineNumber,colNumber,charNumber);
|
||
|
}
|
||
|
int next() {
|
||
|
int c = cin.get();
|
||
|
if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
|
||
|
charNumber++;
|
||
|
return c;
|
||
|
}
|
||
|
private:
|
||
|
std::istream& cin;
|
||
|
ssize_t lineNumber; /// the line number the token is from
|
||
|
ssize_t colNumber; /// the character number in the current line
|
||
|
ssize_t charNumber; /// the character in the file
|
||
|
std::shared_ptr<std::string> name; /// name of buffer
|
||
|
};
|
||
|
|
||
|
/*! creates a stream from a file */
|
||
|
class FileStream : public Stream<int>
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
FileStream (FILE* file, const std::string& name = "file")
|
||
|
: file(file), lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name))) {}
|
||
|
|
||
|
FileStream (const FileName& fileName)
|
||
|
: lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(fileName.str())))
|
||
|
{
|
||
|
file = fopen(fileName.c_str(),"r");
|
||
|
if (file == nullptr) THROW_RUNTIME_ERROR("cannot open file " + fileName.str());
|
||
|
}
|
||
|
~FileStream() { if (file) fclose(file); }
|
||
|
|
||
|
public:
|
||
|
ParseLocation location() {
|
||
|
return ParseLocation(name,lineNumber,colNumber,charNumber);
|
||
|
}
|
||
|
|
||
|
int next() {
|
||
|
int c = fgetc(file);
|
||
|
if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
|
||
|
charNumber++;
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
FILE* file;
|
||
|
ssize_t lineNumber; /// the line number the token is from
|
||
|
ssize_t colNumber; /// the character number in the current line
|
||
|
ssize_t charNumber; /// the character in the file
|
||
|
std::shared_ptr<std::string> name; /// name of buffer
|
||
|
};
|
||
|
|
||
|
/*! creates a stream from a string */
|
||
|
class StrStream : public Stream<int>
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
StrStream (const char* str)
|
||
|
: str(str), lineNumber(1), colNumber(0), charNumber(0) {}
|
||
|
|
||
|
public:
|
||
|
ParseLocation location() {
|
||
|
return ParseLocation(std::shared_ptr<std::string>(),lineNumber,colNumber,charNumber);
|
||
|
}
|
||
|
|
||
|
int next() {
|
||
|
int c = str[charNumber];
|
||
|
if (c == 0) return EOF;
|
||
|
if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++;
|
||
|
charNumber++;
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
const char* str;
|
||
|
ssize_t lineNumber; /// the line number the token is from
|
||
|
ssize_t colNumber; /// the character number in the current line
|
||
|
ssize_t charNumber; /// the character in the file
|
||
|
};
|
||
|
|
||
|
/*! creates a character stream from a command line */
|
||
|
class CommandLineStream : public Stream<int>
|
||
|
{
|
||
|
public:
|
||
|
CommandLineStream (int argc, char** argv, const std::string& name = "command line")
|
||
|
: i(0), j(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name)))
|
||
|
{
|
||
|
if (argc > 0) {
|
||
|
for (size_t i=0; argv[0][i] && i<1024; i++) charNumber++;
|
||
|
charNumber++;
|
||
|
}
|
||
|
for (ssize_t k=1; k<argc; k++) args.push_back(argv[k]);
|
||
|
}
|
||
|
~CommandLineStream() {}
|
||
|
public:
|
||
|
ParseLocation location() {
|
||
|
return ParseLocation(name,0,charNumber,charNumber);
|
||
|
}
|
||
|
int next() {
|
||
|
if (i == args.size()) return EOF;
|
||
|
if (j == args[i].size()) { i++; j=0; charNumber++; return ' '; }
|
||
|
charNumber++;
|
||
|
return args[i][j++];
|
||
|
}
|
||
|
private:
|
||
|
size_t i,j;
|
||
|
std::vector<std::string> args;
|
||
|
ssize_t charNumber; /// the character in the file
|
||
|
std::shared_ptr<std::string> name; /// name of buffer
|
||
|
};
|
||
|
}
|