To learn Rust I want to rewrite an old Project. A very simple arithmetic C++-Parser (only mult and plus). It works as intended in C++. It's not meant to evaluate the arithmetic expression just recognize when parenthesis are mandatory or not (mult and plus).
Example: (5+1) * 2 = (5+1) * 2 but (5 * 1) * 1 = 5 * 1 * 1
I started off trying to implement the equivalent of header files to rust. (I don't want to use bindgen).
There's also ast.h/cpp, parser.h/cpp, but I wanted to start with the tokenizer.
That's the old C++- Tokenizer header:
#ifndef __TOKENIZER__
#define __TOKENIZER__
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef enum {
EOS, // End of string
ZERO,
ONE,
TWO,
OPEN,
CLOSE,
PLUS,
MULT
} Token_t;
string showTok(Token_t t);
// Elementary tokenize(r) class
class Tokenize {
string s;
int pos;
public:
Tokenize(string s) {
this->s = s;
pos = 0;
}
// Scan throuh string, letter (symbol) by letter.
Token_t next();
vector<Token_t> scan();
string show();
};
// Wrapper class, provide the (current) token.
class Tokenizer : Tokenize {
public:
Token_t token;
Tokenizer(string s) : Tokenize(s) { token = next(); }
void nextToken() {
token = next();
}
};
#endif // __TOKENIZER__
And its .cpp
file only as context:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#include "tokenizer.h"
string showTok(Token_t t) {
switch(t) {
case EOS: return "EOS";
case ZERO: return "ZERO";
case ONE: return "ONE";
case TWO: return "TWO";
case OPEN: return "OPEN";
case CLOSE: return "CLOSE";
case PLUS: return "PLUS";
case MULT: return "MULT";
}
}
Token_t Tokenize::next() {
if(s.length() <= pos)
return EOS;
while(1) {
if(s.length() <= pos)
return EOS;
switch(s[pos]) {
case '0': pos++;
return ZERO;
case '1': pos++;
return ONE;
case '2': pos++;
return TWO;
case '(': pos++;
return OPEN;
case ')': pos++;
return CLOSE;
case '+': pos++;
return PLUS;
case '*': pos++;
return MULT;
default:
pos++;
break;
}
}
} // next
vector<Token_t> Tokenize::scan() {
vector<Token_t> v;
Token_t t;
do {
t = next();
v.push_back(t);
}
while(t != EOS);
return v;
} // scan
string Tokenize::show() {
vector<Token_t> v = this->scan();
string s;
for(int i=0; i < v.size(); i++) {
s += showTok(v[i]);
if(i+1 < v.size())
s += ";" ; //delimiter
}
return s;
} // show
And here's my attempt to rewrite the header in Rust:
enum Token_t {
EndOfString,
Zero,
OneExp,
TwoExp,
OpenParan,
CloseParan,
Plus,
Mult,
}
//fn showTok(Token_t: Token)-> string;
struct Tokenize{
str: string,
pos: int
}
trait Tokenize{
fn tokenize(&self)->f64{
self.str = str;
self.pos = pos;
}
fn next()->Tokenize;
fn scan()->vector<Tokenize>;
fn show()-> string;
}
//Wrapper class, provide current Token
trait Tokenizer : Tokenize{
}
My understanding is that Rust equivalent of inheritance works with traits. Is that even the correct start to use them? And "self" should reference the struct field using the point operator . am I using it correctly?