Skip to content

Commit

Permalink
Update API doc config parser.
Browse files Browse the repository at this point in the history
  • Loading branch information
hzeller committed Jan 8, 2020
1 parent 9294f96 commit 4e9627a
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 68 deletions.
104 changes: 53 additions & 51 deletions src/config-parser.cc
Expand Up @@ -29,6 +29,42 @@
#include "common/logging.h"
#include "common/string-util.h"

// Parse a super-simple multiplicative expression.
static double ParseDoubleExpression(const char *input, double fallback,
char **end) {
const char *full_expr = input;
double value = strtod(input, end);
if (*end == input) return fallback;
for (;;) {
while (isspace(**end)) ++*end;
const char op = **end;
if (op != '/' && op != '*') {
return value; // done. Not an operation.
}
++*end;
while (isspace(**end)) ++*end;
input = *end;
double operand;
if (*input == '(') {
operand = ParseDoubleExpression(input+1, 1.0, end);
if (**end != ')') {
fprintf(stderr, "Mismatching parenthesis in '%s'\n", full_expr);
return fallback;
} else {
++*end;
}
} else {
operand = strtod(input, end);
}
if (*end == input) return fallback;
if (op == '/')
value /= operand;
else if (op == '*')
value *= operand;
}
return value;
}

bool ConfigParser::Reader::ParseString(const std::string &value,
std::string *result) {
*result = value;
Expand Down Expand Up @@ -70,44 +106,8 @@ bool ConfigParser::Reader::ParseFloatExpr(const std::string &value,
return false;
}

double ConfigParser::Reader::ParseDoubleExpression(const char *input,
double fallback,
char **end) {
const char *full_expr = input;
double value = strtod(input, end);
if (*end == input) return fallback;
for (;;) {
while (isspace(**end)) ++*end;
const char op = **end;
if (op != '/' && op != '*') {
return value; // done. Not an operation.
}
++*end;
while (isspace(**end)) ++*end;
input = *end;
double operand;
if (*input == '(') {
operand = ParseDoubleExpression(input+1, 1.0, end);
if (**end != ')') {
fprintf(stderr, "Mismatching parenthesis in '%s'\n", full_expr);
return fallback;
} else {
++*end;
}
} else {
operand = strtod(input, end);
}
if (*end == input) return fallback;
if (op == '/')
value /= operand;
else if (op == '*')
value *= operand;
}
return value;
}

void ConfigParser::Reader::ReportError(int line_no, const std::string &msg) {
Log_error("%d: %s", line_no, msg.c_str());
Log_error("Line %d: %s", line_no, msg.c_str());
}

ConfigParser::ConfigParser() : parse_success_(true) {}
Expand All @@ -121,12 +121,13 @@ bool ConfigParser::SetContentFromFile(const char *filename) {
return file_stream.good();
}

void ConfigParser::SetContent(const std::string &content) {
void ConfigParser::SetContent(StringPiece content) {
parse_success_ = true;
content_ = content;
content_ = content.ToString();
}

// Extract next line out of source. Takes
// Extract next line out of source; returns line, modifies "source"
// to point to next
// Modifies source.
static StringPiece NextLine(StringPiece *source) {
StringPiece result;
Expand All @@ -135,12 +136,12 @@ static StringPiece NextLine(StringPiece *source) {
const StringPiece::iterator start = source->begin();
StringPiece::iterator endline = start;
for (/**/; endline != source->end(); ++endline) {
// Whatever comes first terminates our line.
// Whatever newline or comment comes first terminates our resulting line...
if (!result.data() &&
(*endline == '#' || *endline == '\r' || *endline == '\n')) {
result.assign(start, endline - start);
}
if (*endline == '\n') {
if (*endline == '\n') { // ... but we wait until \n to reposition source
source->assign(endline + 1, source->length() - (endline - start) - 1);
return result;
}
Expand All @@ -151,7 +152,7 @@ static StringPiece NextLine(StringPiece *source) {
return result;
}

static std::string CanonicalizeName(const StringPiece &s) {
static std::string CanonicalizeName(const StringPiece s) {
return ToLower(TrimWhitespace(s));
}

Expand Down Expand Up @@ -181,7 +182,7 @@ bool ConfigParser::EmitConfigValues(Reader *reader) {
continue;
}

StringPiece section = line.substr(1, line.length() - 2);
const StringPiece section = line.substr(1, line.length() - 2);
current_section = CanonicalizeName(section);
current_section_interested = reader->SeenSection(line_no, current_section);
}
Expand All @@ -193,17 +194,18 @@ bool ConfigParser::EmitConfigValues(Reader *reader) {
continue;
}
if (current_section_interested) {
std::string name = CanonicalizeName(StringPiece(line.begin(),
eq_pos - line.begin()));
StringPiece value_piece
const std::string name = CanonicalizeName(
StringPiece(line.begin(), eq_pos - line.begin()));
const StringPiece value_piece
= TrimWhitespace(StringPiece(eq_pos + 1, line.end() - eq_pos - 1));
std::string value = value_piece.ToString();
bool could_parse = reader->SeenNameValue(line_no, name, value);
if (!could_parse) {
reader->ReportError(line_no,
StringPrintf("In section [%s]: Couldn't handle '%s = %s'",
current_section.c_str(),
name.c_str(), value.c_str()));
reader->ReportError(
line_no,
StringPrintf("In section [%s]: Couldn't handle '%s = %s'",
current_section.c_str(),
name.c_str(), value.c_str()));
}
success &= could_parse;
}
Expand Down
34 changes: 25 additions & 9 deletions src/config-parser.h
Expand Up @@ -19,12 +19,17 @@
#ifndef _BEAGLEG_CONFIG_PARSER_H
#define _BEAGLEG_CONFIG_PARSER_H

#include <map>
#include <string>
#include <vector>

#include "common/string-util.h"

// The config parser reads a configuration file and passes tokenized
// values to a ConfigParser::Reader.
class ConfigParser {
public:
// A reader has to be implemented by a subsystem that needs configuration
// from the file.
class Reader {
public:
virtual ~Reader() {}
Expand All @@ -44,15 +49,14 @@ class ConfigParser {
virtual void ReportError(int line_no, const std::string &msg);

protected:
// Convenience functions that can be used in derived readers.
// All the Accept() functions are done in the way that they always return
// 'true' if the expected name is not matched, otherwise they return the
// outcome of parsing the value. That way, they can be chained with &&
static bool ParseString(const std::string &value, std::string *result);
static bool ParseInt(const std::string &value, int *result);
static bool ParseBool(const std::string &value, bool *result);
static bool ParseFloatExpr(const std::string &value, float *result);

static double ParseDoubleExpression(const char *input, double fallback, char **end);
};

// Create a config parser.
Expand All @@ -68,17 +72,29 @@ class ConfigParser {
// Set content of configuration file as one string. Typically useful in
// unit tests.
// Overwrites any previous content.
void SetContent(const std::string &content);
void SetContent(StringPiece content);

// Emit configuration values to the Reader. Returns 'true' if
// configuration file could be parsed (no syntax errors, and all calls to
// SeenNameValue() returned true).
// Reader is not taken over.
// Emit configuration values to the Reader for all sections it is interested
// in.
//
// This method can be called many times with different Readers. The
// ConfigParser is handed to various subsystems of the machine-config for
// each of them to configure itself. This allows the ConfigParser to focus on
// tokenization and the configured subsections to ingest name/values.
//
// The parser informes the reader about new sections it has seen
// (calling SeenSection()) and asks if the reader is interested in
// name/value pairs in that section. If so, it provides the reader with these
// calling SeenNameValue().
//
// Returns 'true' if configuration file could be parsed (no syntax errors,
// and all calls to SeenNameValue() returned true).
//
// Reader-ownership is not taken over.
bool EmitConfigValues(Reader *reader);

private:
std::string content_;
bool parse_success_;
std::map<std::string, bool> claimed_sections_;
};
#endif // _BEAGLEG_CONFIG_PARSER_H
4 changes: 0 additions & 4 deletions src/hardware-mapping.cc
Expand Up @@ -398,10 +398,6 @@ class HardwareMapping::ConfigReader : public ConfigParser::Reader {
return false;
}

void ReportError(int line_no, const std::string &msg) final {
Log_error("Line %d: %s", line_no, msg.c_str());
}

private:
bool SetAuxMapping(int line_no, int aux_number, const std::string &value) {
NamedOutput output;
Expand Down
4 changes: 0 additions & 4 deletions src/machine-control-config.cc
Expand Up @@ -116,10 +116,6 @@ class MachineControlConfigReader : public ConfigParser::Reader {
return false;
}

void ReportError(int line_no, const std::string &msg) final {
Log_error("Line %d: %s", line_no, msg.c_str());
}

private:
bool SetHomePos(int line_no, enum GCodeParserAxis axis,
const std::string &value) {
Expand Down

0 comments on commit 4e9627a

Please sign in to comment.