First template implementation for c++
This commit is contained in:
parent
8a59d19e5c
commit
d17dc608dc
|
@ -0,0 +1,108 @@
|
||||||
|
#include "{{name}}.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace { //The automaton data
|
||||||
|
typedef unsigned long long State;
|
||||||
|
|
||||||
|
State REJECT = {{reject_state}};
|
||||||
|
|
||||||
|
char TRANS_IDX[256] = { {{#trans_idx}}{{trans}}, {{/trans_idx}} };
|
||||||
|
|
||||||
|
State TABLE[{{num_states}}][{{num_transitions_per_state}}] = { {{#table}}
|
||||||
|
{ {{#row}} {{state}}, {{/row}} },
|
||||||
|
{{/table}} };
|
||||||
|
|
||||||
|
{{name}}::TokenType TOKENS[{{num_states}}] = { {{#tokens}} {{name}}::{{token}}, {{/tokens}} };
|
||||||
|
}
|
||||||
|
|
||||||
|
{{name}}::{{name}}(std::istream& in) : m_offset(0), m_input(in) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{{name}}::~{{name}}() {
|
||||||
|
}
|
||||||
|
|
||||||
|
{{name}}::Token {{name}}::nextToken() {
|
||||||
|
TRANS_IDX['a'] = 1;
|
||||||
|
TRANS_IDX['b'] = 2;
|
||||||
|
TokenType type = ignore;
|
||||||
|
std::string token;
|
||||||
|
|
||||||
|
while (type == ignore) {
|
||||||
|
State state = 0;
|
||||||
|
std::size_t match_length = 0;
|
||||||
|
token = "";
|
||||||
|
|
||||||
|
while (!m_input.eof() && state != REJECT) {
|
||||||
|
char c = m_input.peek();
|
||||||
|
if (m_input.eof())
|
||||||
|
break;
|
||||||
|
|
||||||
|
token += c;
|
||||||
|
|
||||||
|
state = TABLE[state][TRANS_IDX[c]];
|
||||||
|
if (TOKENS[state])
|
||||||
|
{
|
||||||
|
match_length = token.length();
|
||||||
|
type = TOKENS[state];
|
||||||
|
}
|
||||||
|
m_input.get();
|
||||||
|
++m_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t sdiff = token.length() - match_length;
|
||||||
|
for (std::size_t i = 0; i < sdiff; i++)
|
||||||
|
{
|
||||||
|
m_input.putback(token[token.length() - i - 1]);
|
||||||
|
}
|
||||||
|
m_offset -= sdiff;
|
||||||
|
|
||||||
|
if (!type || !match_length) {
|
||||||
|
if (m_input.eof())
|
||||||
|
throw NoMoreTokens();
|
||||||
|
throw NoMatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
token = token.substr(0, match_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token t;
|
||||||
|
t.type = type;
|
||||||
|
t.content = token;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void {{name}}::skip(std::size_t n) {
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
m_input.get();
|
||||||
|
++m_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char {{name}}::peek() {
|
||||||
|
if (m_input.eof())
|
||||||
|
throw NoMoreTokens();
|
||||||
|
return m_input.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t {{name}}::getByteOffset() {
|
||||||
|
return m_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Temporary main
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
std::istringstream in(argv[1]);
|
||||||
|
{{name}} lex(in);
|
||||||
|
try {
|
||||||
|
while (true)
|
||||||
|
std::cout << "Match: " << lex.nextToken().content << std::endl;
|
||||||
|
}
|
||||||
|
catch (decltype(lex)::NoMoreTokens& err) {
|
||||||
|
std::cout << "DONE, read " << lex.getByteOffset() << " bytes." << std::endl;
|
||||||
|
}
|
||||||
|
catch (decltype(lex)::NoMatch& err) {
|
||||||
|
std::cout << "No match, " << lex.getByteOffset() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
#pragma once
|
||||||
|
#ifndef LEXER_{{name}}_H
|
||||||
|
#define LEXER_{{name}}_H
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <istream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class {{name}} {
|
||||||
|
public:
|
||||||
|
class NoMoreTokens : public std::exception {};
|
||||||
|
class NoMatch : public std::exception {};
|
||||||
|
|
||||||
|
enum TokenType {
|
||||||
|
nonmatching,
|
||||||
|
{{#token_types}}
|
||||||
|
{{type}},
|
||||||
|
{{/token_types}}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Token {
|
||||||
|
TokenType type;
|
||||||
|
std::string content;
|
||||||
|
};
|
||||||
|
|
||||||
|
{{name}}(std::istream& in);
|
||||||
|
~{{name}}();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next token
|
||||||
|
*
|
||||||
|
* @throws NoMoreTokens if no more tokens are available
|
||||||
|
* @throws NoMatch if no match was found
|
||||||
|
*/
|
||||||
|
Token nextToken();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip the following `n` bytes.
|
||||||
|
*
|
||||||
|
* @param n The number of bytes to skip
|
||||||
|
*/
|
||||||
|
void skip(std::size_t n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peek at the current head of the input stream, useful in error reporting when a character mismatches for example
|
||||||
|
*
|
||||||
|
* @throws NoMoreTokens if the input stream is at an end
|
||||||
|
*/
|
||||||
|
char peek();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current byte offset
|
||||||
|
*/
|
||||||
|
std::size_t getByteOffset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t m_offset;
|
||||||
|
std::istream& m_input;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //LEXER_{{name}}_H
|
Loading…
Reference in New Issue