Files
secondo/Algebras/FixedMRegion/fmr/RList.cpp
2026-01-23 17:03:45 +08:00

360 lines
6.9 KiB
C++

/*
----
* This file is part of libfmr
*
* File: RList.cpp
* Author: Florian Heinz <fh@sysv.de>
*
* Created on September 6, 2016, 11:48 AM
----
//paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}]
//[TOC] [\tableofcontents]
[1] Implementation of the class ~RList~
[TOC]
1 Overview
RLists are a form of nested lists used to represent the various objecttypes
in this library. It is used to convert from/to a textual representation or
from/to foreign objects.
*/
#include "fmr_RList.h"
#include <sstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "satof.h"
using namespace fmr;
/*
2 Constructor
Creates an empty nested list.
*/
RList::RList() : type(NL_LIST) {
}
/*
3 ~append~ double
Appends a real number to this list.
*/
void RList::append(double nr) {
RList nl;
nl.type = NL_DOUBLE;
nl.nr = nr;
items.push_back(nl);
}
/*
4 ~append~ string
Appends a string to this list.
*/
void RList::append(std::string str) {
RList nl;
nl.type = NL_STRING;
nl.str.append(str);
items.push_back(nl);
}
/*
5 ~appendSym~ string
Appends a symbol to this list.
*/
void RList::appendSym(std::string str) {
RList nl;
nl.type = NL_SYM;
nl.str.append(str);
items.push_back(nl);
}
/*
6 ~append~ bool
Appends a boolean value to this list.
*/
void RList::append(bool val) {
RList nl;
nl.type = NL_BOOL;
nl.boolean = val;
items.push_back(nl);
}
/*
7 ~append~ RList
Appends a sublist to this list.
*/
void RList::append(RList l) {
items.push_back(l);
}
/*
8 ~nest~
Appends a new, empty nested list to this nested
list and returns a reference to it.
*/
RList& RList::nest() {
RList nl;
nl.type = NL_LIST;
items.push_back(nl);
return items[items.size() - 1];
}
/*
9 ~concat~
Appends the items of a given list to this list.
*/
void RList::concat(RList l) {
items.insert(items.end(), l.items.begin(), l.items.end());
}
// Perform indentation for string output
static std::string do_indent(int indent) {
std::string ret;
ret.append("\n");
while (indent--)
ret.append(" ");
return ret;
}
/*
10 ~ToString~
Creates a string representation from this
list with a given indentation level.
*/
std::string RList::ToString(int indent) {
std::stringstream ret;
if (type == NL_LIST) {
ret << do_indent(indent);
ret << "( ";
for (unsigned int i = 0; i < items.size(); i++) {
ret << items[i].ToString(indent + 1);
ret << " ";
}
ret << ")";
} else if (type == NL_DOUBLE) {
ret << nr;
} else if (type == NL_BOOL) {
ret << (boolean ? "TRUE" : "FALSE");
} else if (type == NL_STRING) {
ret << "\"" << str << "\"";
} else if (type == NL_SYM) {
ret << "" << str << "";
}
return ret.str();
}
/*
11 ~ToString~
Creates a string representation from this nested list.
*/
std::string RList::ToString() {
return ToString(0);
}
/*
12 ~SecondoObject~
Constructs a Secondo-compatible object with name ~name~ and type
~type~ from this nested list. Useful for saving object files,
which can be read in by secondo.
*/
RList RList::SecondoObject(std::string name, std::string type) {
RList ret;
ret.appendSym("OBJECT");
ret.appendSym(name);
ret.nest();
ret.appendSym(type);
ret.append(*this);
return ret;
}
/*
13 Parser
Parses an RList from a file.
*/
#define NUM 257
#define STRING 258
#define SYM 259
#define BOOL 260
static double num;
static std::string str;
static bool b;
static int getToken(FILE *f) {
char buf[1024], *ptr = buf;
int curtype = 0;
do {
int ch = fgetc(f);
switch (ch) {
case ')':
case '(':
if (buf == ptr)
return ch;
case ' ':
case '\r':
case '\n':
case '\t':
if (buf != ptr) {
ungetc(ch, f);
int _curtype = curtype;
curtype = 0;
switch (_curtype) {
case NUM:
num = satof(buf);
return NUM;
case SYM:
if (!strcasecmp(buf, "TRUE")) {
b = true;
return BOOL;
} else if (!strcasecmp(buf, "FALSE")) {
b = false;
return BOOL;
} else {
str = buf;
return SYM;
}
case STRING:
str = buf;
return STRING;
}
return curtype;
}
break;
case EOF:
return 0;
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
if (curtype == 0)
curtype = NUM;
case '"':
if (curtype == 0) {
curtype = STRING;
break;
} else if (curtype == STRING && ch == '"')
break;
default:
if (curtype == 0)
curtype = SYM;
*ptr++ = ch;
*ptr = '\0';
break;
}
} while (!feof(f));
return 0;
}
// Parse the textual nested list and create a
// RList-object from it (a simple parser).
static void parse(FILE *f, RList& nl, int depth) {
do {
int token = getToken(f);
switch (token) {
case '(':
parse(f, nl.nest(), depth+1);
break;
case NUM:
nl.append(num);
break;
case STRING:
nl.append(str);
break;
case BOOL:
nl.append(b);
break;
case SYM:
nl.appendSym(str);
break;
case ')':
return;
default:
return;
}
} while (1);
}
/*
14 ~parseFile~
Parse the given file with the textual representation of a list
and return a corresponding RList object.
*/
RList RList::parseFile(std::string filename) {
FILE *f;
RList ret;
f = fopen(filename.c_str(), "r");
if (!f)
return ret;
if (getToken(f) != '(') {
printf("Parse error! (Beginning)\n");
return ret;
} else {
parse(f, ret, 0);
if (getToken(f) != 0) {
printf("Parse error! (End)\n");
return ret;
}
}
fclose(f);
return ret;
}