190 lines
5.4 KiB
C++
190 lines
5.4 KiB
C++
/*
|
|
* nextpnr -- Next Generation Place and Route
|
|
*
|
|
* Copyright (C) 2022 gatecat <gatecat@ds0.me>
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
#ifndef FABULOUS_PARSING_H
|
|
#define FABULOUS_PARSING_H
|
|
|
|
#include <iostream>
|
|
#include <limits>
|
|
#include <string>
|
|
#include "idstring.h"
|
|
#include "nextpnr_assertions.h"
|
|
#include "nextpnr_namespaces.h"
|
|
|
|
NEXTPNR_NAMESPACE_BEGIN
|
|
|
|
struct BaseCtx;
|
|
|
|
// Lightweight NIH string_view
|
|
struct parser_view
|
|
{
|
|
char *m_ptr;
|
|
size_t m_length;
|
|
parser_view() : m_ptr(nullptr), m_length(0) {};
|
|
explicit parser_view(std::string &str) : m_ptr(&(str[0])), m_length(str.size()) {};
|
|
parser_view(char *ptr, size_t length) : m_ptr(ptr), m_length(length) {};
|
|
|
|
static constexpr size_t npos = std::numeric_limits<size_t>::max();
|
|
char operator[](size_t idx)
|
|
{
|
|
NPNR_ASSERT(idx < m_length);
|
|
return m_ptr[idx];
|
|
}
|
|
|
|
size_t size() const { return m_length; }
|
|
|
|
bool empty() const { return m_length == 0; }
|
|
|
|
parser_view substr(size_t start, size_t length = npos)
|
|
{
|
|
NPNR_ASSERT(start <= m_length);
|
|
if (length == npos)
|
|
length = m_length - start;
|
|
NPNR_ASSERT(length <= m_length);
|
|
return parser_view(m_ptr + start, length);
|
|
}
|
|
|
|
size_t find(char tok) const
|
|
{
|
|
for (size_t i = 0; i < m_length; i++)
|
|
if (m_ptr[i] == tok)
|
|
return i;
|
|
return npos;
|
|
}
|
|
|
|
size_t rfind(char tok) const
|
|
{
|
|
for (size_t i = m_length; i > 0; i--)
|
|
if (m_ptr[i - 1] == tok)
|
|
return i - 1;
|
|
return npos;
|
|
}
|
|
|
|
IdString to_id(const BaseCtx *ctx)
|
|
{
|
|
// This isn't really ideal, let's hope one day we can move to C++20 and have proper string_views instead :3
|
|
char tmp = m_ptr[m_length];
|
|
m_ptr[m_length] = '\0';
|
|
IdString id = IdString(ctx, m_ptr);
|
|
m_ptr[m_length] = tmp;
|
|
return id;
|
|
}
|
|
|
|
long to_int()
|
|
{
|
|
// This isn't really ideal, let's hope one day we can move to C++20 and have proper string_views instead :3
|
|
char tmp = m_ptr[m_length];
|
|
m_ptr[m_length] = '\0';
|
|
long l = strtol(m_ptr, nullptr, 0);
|
|
m_ptr[m_length] = tmp;
|
|
return l;
|
|
}
|
|
|
|
parser_view strip(const std::string &ws = " \r\n\t")
|
|
{
|
|
char *ptr = m_ptr;
|
|
size_t length = m_length;
|
|
while (length > 0) { // strip front
|
|
if (ws.find(*ptr) == std::string::npos) // not whitespace
|
|
break;
|
|
ptr++;
|
|
length--;
|
|
}
|
|
while (length > 0) { // strip back
|
|
if (ws.find(ptr[length - 1]) == std::string::npos) // not whitespace
|
|
break;
|
|
length--;
|
|
}
|
|
return parser_view(ptr, length);
|
|
}
|
|
|
|
char back()
|
|
{
|
|
NPNR_ASSERT(m_length > 0);
|
|
return m_ptr[m_length - 1];
|
|
}
|
|
|
|
parser_view back(size_t count)
|
|
{
|
|
NPNR_ASSERT(count <= m_length);
|
|
return parser_view(m_ptr + (m_length - count), count);
|
|
}
|
|
|
|
bool starts_with(const std::string &st)
|
|
{
|
|
if (m_length < st.size())
|
|
return false;
|
|
for (size_t i = 0; i < st.length(); i++)
|
|
if (m_ptr[i] != st[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
std::pair<parser_view, parser_view> split(char delim) const
|
|
{
|
|
size_t pos = find(delim);
|
|
NPNR_ASSERT(pos != npos);
|
|
return std::make_pair(parser_view(m_ptr, pos), parser_view(m_ptr + pos + 1, m_length - (pos + 1)));
|
|
}
|
|
std::pair<parser_view, parser_view> rsplit(char delim) const
|
|
{
|
|
size_t pos = rfind(delim);
|
|
NPNR_ASSERT(pos != npos);
|
|
return std::make_pair(parser_view(m_ptr, pos), parser_view(m_ptr + pos + 1, m_length - (pos + 1)));
|
|
}
|
|
};
|
|
|
|
struct CsvParser
|
|
{
|
|
explicit CsvParser(std::istream &in) : in(in) {};
|
|
std::istream ∈
|
|
std::string buf;
|
|
parser_view view;
|
|
bool fetch_next_line()
|
|
{
|
|
while (!in.eof()) {
|
|
std::getline(in, buf);
|
|
view = parser_view(buf).strip();
|
|
size_t end_pos = view.find('#');
|
|
if (end_pos != parser_view::npos)
|
|
view = view.substr(0, end_pos);
|
|
view = view.strip();
|
|
if (!view.empty())
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
parser_view next_field()
|
|
{
|
|
size_t next_delim = view.find(',');
|
|
if (next_delim == parser_view::npos) {
|
|
parser_view result = view.substr(0, next_delim);
|
|
view = parser_view();
|
|
return result;
|
|
} else {
|
|
parser_view result = view.substr(0, next_delim);
|
|
view = view.substr(next_delim + 1);
|
|
return result;
|
|
}
|
|
}
|
|
};
|
|
|
|
NEXTPNR_NAMESPACE_END
|
|
|
|
#endif
|