Playing with a comparison of python vs. c++ for something simple. stats.py reads lines on stdin and outputs some json, and goc.cpp reads stdin and outputs csv. I may just go with csv for the project but I'll see what json is like in C++ too.
parent
6a777e4c2d
commit
567ffec4ac
@ -0,0 +1,6 @@ |
|||||||
|
|
||||||
|
all: |
||||||
|
meson compile -C .
|
||||||
|
|
||||||
|
test: |
||||||
|
@echo "../ex08.cpp:7:10: error: use of undeclared identifier \'oops\'" | ../builddir/goc
|
@ -0,0 +1,238 @@ |
|||||||
|
/*
|
||||||
|
* Same code as ex06.cpp but I use auto everywhere I could to |
||||||
|
* see how it works. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <iostream> |
||||||
|
#include <queue> |
||||||
|
using namespace std; |
||||||
|
|
||||||
|
class Error { |
||||||
|
public: |
||||||
|
string message; |
||||||
|
|
||||||
|
Error(string m) : message{m} {}; |
||||||
|
}; |
||||||
|
|
||||||
|
enum class TokenKind { |
||||||
|
SEMI_COLON, |
||||||
|
QUIT, |
||||||
|
LPAREN, |
||||||
|
RPAREN, |
||||||
|
PLUS, |
||||||
|
MINUS, |
||||||
|
MULT, |
||||||
|
DIV, |
||||||
|
NUMBER, |
||||||
|
NAME, |
||||||
|
EQ, |
||||||
|
ERROR |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
class Token { |
||||||
|
public: |
||||||
|
TokenKind kind = TokenKind::ERROR; |
||||||
|
double value = 0.0; |
||||||
|
string name = ""; |
||||||
|
|
||||||
|
Token(TokenKind k) : kind(k) {} |
||||||
|
|
||||||
|
Token(TokenKind k, double v) : kind{k}, value{v} {} |
||||||
|
|
||||||
|
Token(TokenKind k, string n) : kind{k}, name{n}{} |
||||||
|
}; |
||||||
|
|
||||||
|
class TokenStream { |
||||||
|
public: |
||||||
|
auto get() { |
||||||
|
if(!buffer.empty()) { |
||||||
|
auto first = buffer.front(); |
||||||
|
buffer.pop(); |
||||||
|
return first; |
||||||
|
} |
||||||
|
|
||||||
|
char ch = 0; |
||||||
|
if(!(cin >> ch)) throw Error{"no input"}; |
||||||
|
|
||||||
|
switch(ch) { |
||||||
|
case ';': return Token{TokenKind::SEMI_COLON}; |
||||||
|
case 'q': return Token{TokenKind::QUIT}; |
||||||
|
case '(': return Token{TokenKind::LPAREN}; |
||||||
|
case ')': return Token{TokenKind::RPAREN}; |
||||||
|
case '+': return Token{TokenKind::PLUS}; |
||||||
|
case '-': return Token{TokenKind::MINUS}; |
||||||
|
case '*': return Token{TokenKind::MULT}; |
||||||
|
case '/': return Token{TokenKind::DIV}; |
||||||
|
case '.': |
||||||
|
case '0': // fallthrough
|
||||||
|
case '1': // fallthrough
|
||||||
|
case '2': // fallthrough
|
||||||
|
case '3': // fallthrough
|
||||||
|
case '4': |
||||||
|
case '5': // fallthrough
|
||||||
|
case '6': // fallthrough
|
||||||
|
case '7': // fallthrough
|
||||||
|
case '8': // fallthrough
|
||||||
|
case '9': // falltrhough
|
||||||
|
{ |
||||||
|
cin.putback(ch); |
||||||
|
auto val = 0.0; |
||||||
|
cin >> val; |
||||||
|
return Token{TokenKind::NUMBER, val}; |
||||||
|
} |
||||||
|
case '=': |
||||||
|
return Token{TokenKind::EQ}; |
||||||
|
default: |
||||||
|
if(isalpha(ch)) { |
||||||
|
cin.putback(ch); |
||||||
|
string s; |
||||||
|
cin >> s; |
||||||
|
return Token{TokenKind::NAME, s}; |
||||||
|
} else { |
||||||
|
throw Error{"bad token"}; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void putback(Token t) { |
||||||
|
buffer.push(t); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
queue<Token> buffer; |
||||||
|
}; |
||||||
|
|
||||||
|
class Variable { |
||||||
|
public: |
||||||
|
string name; |
||||||
|
double value; |
||||||
|
}; |
||||||
|
|
||||||
|
vector<Variable> var_table; |
||||||
|
|
||||||
|
double get_value(string s) { |
||||||
|
for(const Variable& v : var_table) { |
||||||
|
if(v.name == s) { |
||||||
|
return v.value; |
||||||
|
} |
||||||
|
} |
||||||
|
throw Error{"variable not found"}; |
||||||
|
} |
||||||
|
|
||||||
|
void set_value(string s, double d) |
||||||
|
{ |
||||||
|
for(Variable& v : var_table) { |
||||||
|
if(v.name == s) { |
||||||
|
v.value = d; |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// variable not found make it
|
||||||
|
var_table.push_back(Variable{s, d}); |
||||||
|
} |
||||||
|
|
||||||
|
Token parse(TokenStream &stream); |
||||||
|
|
||||||
|
Token expression(TokenStream &stream) { |
||||||
|
auto lval = stream.get(); |
||||||
|
auto op = stream.get(); |
||||||
|
auto rval = stream.get(); |
||||||
|
double result = 0; |
||||||
|
|
||||||
|
// parens start a sub-expression
|
||||||
|
if(rval.kind == TokenKind::LPAREN) { |
||||||
|
rval = expression(stream); |
||||||
|
// eat the RPAREN
|
||||||
|
auto rparen = stream.get(); |
||||||
|
if(rparen.kind != TokenKind::RPAREN) { |
||||||
|
throw Error{"expected RPAREN"}; |
||||||
|
} |
||||||
|
} else if(rval.kind == TokenKind::NAME) { |
||||||
|
auto var_val = get_value(rval.name); |
||||||
|
rval = Token{TokenKind::NUMBER, var_val}; |
||||||
|
} |
||||||
|
|
||||||
|
switch(op.kind) { |
||||||
|
case TokenKind::PLUS: |
||||||
|
result = lval.value + rval.value; |
||||||
|
break; |
||||||
|
case TokenKind::MINUS: |
||||||
|
result = lval.value - rval.value; |
||||||
|
break; |
||||||
|
case TokenKind::DIV: |
||||||
|
result = lval.value / rval.value; |
||||||
|
break; |
||||||
|
case TokenKind::MULT: |
||||||
|
result = lval.value * rval.value; |
||||||
|
default: |
||||||
|
throw Error{"invalid syntax in expresion"}; |
||||||
|
} |
||||||
|
|
||||||
|
return Token{TokenKind::NUMBER, result}; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
Token parse(TokenStream &stream) { |
||||||
|
auto tok = stream.get(); |
||||||
|
|
||||||
|
switch(tok.kind) { |
||||||
|
case TokenKind::NUMBER: |
||||||
|
stream.putback(tok); |
||||||
|
return expression(stream); |
||||||
|
case TokenKind::NAME: { |
||||||
|
auto eq = stream.get(); |
||||||
|
|
||||||
|
if(eq.kind == TokenKind::EQ) { |
||||||
|
auto val = stream.get(); |
||||||
|
if(val.kind != TokenKind::NUMBER) throw Error{"invalid value in variable assign"}; |
||||||
|
|
||||||
|
set_value(tok.name, val.value); |
||||||
|
return val; |
||||||
|
} else { |
||||||
|
auto var_val = get_value(tok.name); |
||||||
|
stream.putback(Token{TokenKind::NUMBER, var_val}); |
||||||
|
stream.putback(eq); // push the next token back on
|
||||||
|
return expression(stream); |
||||||
|
} |
||||||
|
} |
||||||
|
case TokenKind::LPAREN: { |
||||||
|
auto val = expression(stream); |
||||||
|
tok = stream.get(); |
||||||
|
if(tok.kind != TokenKind::RPAREN) { |
||||||
|
throw Error{"missing rparen"}; |
||||||
|
} |
||||||
|
return val; |
||||||
|
} |
||||||
|
case TokenKind::QUIT: |
||||||
|
return tok; |
||||||
|
default: |
||||||
|
cout << "Got token " << ":" << tok.value << " expected NUMBER or LPAREN\n"; |
||||||
|
throw Error{"invalid syntax in parse"}; |
||||||
|
} |
||||||
|
|
||||||
|
return Token{TokenKind::ERROR}; |
||||||
|
} |
||||||
|
|
||||||
|
int main() { |
||||||
|
TokenStream stream; |
||||||
|
|
||||||
|
while(cin) { |
||||||
|
try { |
||||||
|
auto val = parse(stream); |
||||||
|
|
||||||
|
if(val.kind == TokenKind::ERROR) { |
||||||
|
cout << "Parse returned an error token.\n"; |
||||||
|
} else if(val.kind == TokenKind::QUIT) { |
||||||
|
cout << "Goodbye!\n"; |
||||||
|
return 0; |
||||||
|
} else { |
||||||
|
cout << "=" << val.value << "\n"; |
||||||
|
} |
||||||
|
} catch (Error &err) { |
||||||
|
cout << "ERROR " << err.message << "\n"; |
||||||
|
} |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
#include <iostream> |
||||||
|
|
||||||
|
using namespace std; |
||||||
|
|
||||||
|
int main() |
||||||
|
{ |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
#include <iostream> |
||||||
|
#include <fmt/core.h> |
||||||
|
#include <regex> |
||||||
|
#include <string> |
||||||
|
#include <iterator> |
||||||
|
|
||||||
|
using namespace std; |
||||||
|
using namespace fmt; |
||||||
|
|
||||||
|
int main() |
||||||
|
{ |
||||||
|
regex err_re("(.*?):([0-9]+):([0-9]+):\\s*(.*?):\\s*(.*)"); |
||||||
|
string line; |
||||||
|
smatch err_match; |
||||||
|
|
||||||
|
while(getline(cin, line)) { |
||||||
|
print("{}\n", line); |
||||||
|
if(regex_match(line, err_match, err_re)) { |
||||||
|
string file_name = err_match[1].str(); |
||||||
|
string line = err_match[2].str(); |
||||||
|
string col = err_match[3].str(); |
||||||
|
string type = err_match[4].str(); |
||||||
|
string message = err_match[5].str(); |
||||||
|
|
||||||
|
print("{},{},{},{},{}\n", |
||||||
|
file_name, line, col, type, message); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -1,9 +1,18 @@ |
|||||||
project('lcppthw', 'cpp', |
project('lcppthw', 'cpp', |
||||||
default_options: ['cpp_std=c++20']) |
default_options: ['cpp_std=c++20']) |
||||||
|
|
||||||
|
fmt_dep = dependency('fmt') |
||||||
|
|
||||||
|
executable('goc', 'goc.cpp', |
||||||
|
win_subsystem: 'windows', |
||||||
|
cpp_args: '-DFMT_HEADER_ONLY', |
||||||
|
dependencies: fmt_dep) |
||||||
|
|
||||||
executable('ex01', 'ex01.cpp') |
executable('ex01', 'ex01.cpp') |
||||||
executable('ex02', 'ex02.cpp') |
executable('ex02', 'ex02.cpp') |
||||||
executable('ex03', 'ex03.cpp') |
executable('ex03', 'ex03.cpp') |
||||||
executable('ex04', 'ex04.cpp') |
executable('ex04', 'ex04.cpp') |
||||||
executable('ex05', 'ex05.cpp') |
executable('ex05', 'ex05.cpp') |
||||||
executable('ex06', 'ex06.cpp') |
executable('ex06', 'ex06.cpp') |
||||||
|
executable('ex07', 'ex07.cpp') |
||||||
|
executable('ex08', 'ex08.cpp') |
||||||
|
@ -0,0 +1,21 @@ |
|||||||
|
import sys |
||||||
|
import re |
||||||
|
import json |
||||||
|
from datetime import datetime |
||||||
|
|
||||||
|
err_re = re.compile("(?P<file>.*?):(?P<line>[0-9]+):(?P<col>[0-9]+): (?P<type>.*?): (?P<message>.*)\n") |
||||||
|
|
||||||
|
stats = []; |
||||||
|
|
||||||
|
for line in sys.stdin: |
||||||
|
found = err_re.fullmatch(line) |
||||||
|
print(line, end="") |
||||||
|
|
||||||
|
if found: |
||||||
|
stats.append(found.groupdict()) |
||||||
|
print("FOUND", found.groupdict()) |
||||||
|
|
||||||
|
with open("stats.json", "a+") as out: |
||||||
|
out.write(json.dumps({"date": datetime.now().isoformat(), |
||||||
|
"messages": stats})); |
||||||
|
out.write("\n") |
Loading…
Reference in new issue