package def parsing
This commit is contained in:
@@ -1 +1 @@
|
||||
Checks: '*,clang-analyzer-*,-llvmlibc-*,-fuchsia-*,-altera-*,-abseil-*,-android-*,-modernize-use-trailing-return-type,-readability-identifier-length,-*-readability-todo,-*-magic-numbers,-readability-function-cognitive-complexity,-*-easily-swappable-parameters'
|
||||
Checks: '*,clang-analyzer-*,-llvmlibc-*,-fuchsia-*,-altera-*,-abseil-*,-android-*,-modernize-use-trailing-return-type,-readability-identifier-length,-*-readability-todo,-*-magic-numbers,-readability-function-cognitive-complexity,-*-easily-swappable-parameters,-*-non-private-member-variables-in-classes,-*-no-recursion'
|
||||
17
src/main.cc
17
src/main.cc
@@ -1,3 +1,18 @@
|
||||
#include "parser.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
int main() { std::cout << "Hello, World!\n"; }
|
||||
int main() {
|
||||
std::ifstream file("zlib.shrap");
|
||||
if (!file) {
|
||||
std::cerr << "Error opening file\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
|
||||
Expr pkg = Expr::parse(buffer.str());
|
||||
std::cout << pkg.get("name").value << std::endl;
|
||||
}
|
||||
141
src/parser.h
Normal file
141
src/parser.h
Normal file
@@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct Expr {
|
||||
public:
|
||||
enum class Type { Atom, String, List };
|
||||
|
||||
Type type = Type::Atom;
|
||||
std::string value;
|
||||
std::vector<Expr> children;
|
||||
|
||||
[[nodiscard]] Expr get(const std::string &key) const {
|
||||
if (type != Type::List) {
|
||||
throw std::runtime_error("get() called on non-list");
|
||||
}
|
||||
for (const auto &child : children) {
|
||||
if (child.type == Type::List && child.children.size() >= 2 &&
|
||||
child.children[0].type == Type::Atom &&
|
||||
child.children[0].value == key) {
|
||||
return child.children[1];
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("key not found: " + key);
|
||||
}
|
||||
|
||||
static Expr parse(const std::string &input) {
|
||||
std::istringstream in(input);
|
||||
return parse_expr(in);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string read_atom(std::istringstream &in) {
|
||||
std::string atom;
|
||||
while (true) {
|
||||
int next = in.peek();
|
||||
if (next == -1 || is_space(static_cast<char>(next)) || next == '(' ||
|
||||
next == ')') {
|
||||
break;
|
||||
}
|
||||
atom += static_cast<char>(in.get());
|
||||
}
|
||||
if (atom.empty()) {
|
||||
throw std::runtime_error("empty atom");
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
|
||||
static Expr parse_list(std::istringstream &in) {
|
||||
Expr result = {.type = Expr::Type::List};
|
||||
|
||||
in.get(); // consume bracket
|
||||
|
||||
while (true) {
|
||||
while (is_space(static_cast<char>(in.peek()))) {
|
||||
in.get();
|
||||
}
|
||||
if (!in) {
|
||||
throw std::runtime_error("unexpected EOF");
|
||||
}
|
||||
|
||||
if (in.peek() == ')') {
|
||||
in.get();
|
||||
break;
|
||||
}
|
||||
|
||||
result.children.push_back(parse_expr(in));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string read_string(std::istringstream &in) {
|
||||
std::string result;
|
||||
|
||||
in.get(); // consume the quote
|
||||
|
||||
while (true) {
|
||||
if (!in) {
|
||||
throw std::runtime_error("unexpected EOF in string");
|
||||
}
|
||||
|
||||
auto c = static_cast<char>(in.get());
|
||||
if (c == '"') {
|
||||
break;
|
||||
}
|
||||
result += c;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static Expr parse_expr(std::istringstream &in) {
|
||||
while (is_space(static_cast<char>(in.peek()))) {
|
||||
in.get();
|
||||
}
|
||||
if (!in) {
|
||||
throw std::runtime_error("unexpected EOF");
|
||||
}
|
||||
|
||||
if (in.peek() == '(') {
|
||||
return parse_list(in);
|
||||
}
|
||||
if (in.peek() == ')') {
|
||||
throw std::runtime_error("unexpected ')'");
|
||||
}
|
||||
|
||||
if (in.peek() == '"') {
|
||||
return {.type = Type::String, .value = read_string(in)};
|
||||
}
|
||||
|
||||
return {.type = Type::Atom, .value = read_atom(in)};
|
||||
}
|
||||
|
||||
static bool is_space(char c) {
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\r';
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &out, const Expr &e) {
|
||||
switch (e.type) {
|
||||
case Expr::Type::Atom:
|
||||
out << e.value;
|
||||
break;
|
||||
case Expr::Type::String:
|
||||
out << '"' << e.value << '"';
|
||||
break;
|
||||
case Expr::Type::List:
|
||||
out << '(';
|
||||
for (size_t i = 0; i < e.children.size(); ++i) {
|
||||
if (i > 0) {
|
||||
out << ' ';
|
||||
}
|
||||
out << e.children[i];
|
||||
}
|
||||
out << ')';
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
7
zlib.shrap
Normal file
7
zlib.shrap
Normal file
@@ -0,0 +1,7 @@
|
||||
(package
|
||||
(name "zlib")
|
||||
(version "1.3.1")
|
||||
(homepage "https://zlib.net/")
|
||||
(src (tar "https://zlib.net/zlib-1.3.1.tar.gz" "207c3b0862cb4e3686f8405f76a98c38dbad9c94bcf4be4b9efca0716aba51ec"))
|
||||
(build
|
||||
(configure_make)))
|
||||
Reference in New Issue
Block a user