2021-03-17 23:04:36 +00:00
|
|
|
import 'dart:math';
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:combinator/combinator.dart';
|
|
|
|
import 'package:string_scanner/string_scanner.dart';
|
|
|
|
|
|
|
|
/// Note: This grammar does not handle precedence, for the sake of simplicity.
|
|
|
|
Parser<num> calculatorGrammar() {
|
|
|
|
var expr = reference<num>();
|
|
|
|
|
|
|
|
var number = match<num>(new RegExp(r'-?[0-9]+(\.[0-9]+)?'))
|
2021-03-18 00:00:56 +00:00
|
|
|
.value((r) => num.parse(r.span!.text));
|
2021-03-17 23:04:36 +00:00
|
|
|
|
|
|
|
var hex = match<int>(new RegExp(r'0x([A-Fa-f0-9]+)'))
|
2021-03-18 00:00:56 +00:00
|
|
|
.map((r) => int.parse(r.scanner.lastMatch![1]!, radix: 16));
|
2021-03-17 23:04:36 +00:00
|
|
|
|
|
|
|
var binary = match<int>(new RegExp(r'([0-1]+)b'))
|
2021-03-18 00:00:56 +00:00
|
|
|
.map((r) => int.parse(r.scanner.lastMatch![1]!, radix: 2));
|
2021-03-17 23:04:36 +00:00
|
|
|
|
|
|
|
var alternatives = <Parser<num>>[];
|
|
|
|
|
|
|
|
void registerBinary(String op, num Function(num, num) f) {
|
|
|
|
alternatives.add(
|
|
|
|
chain<num>([
|
|
|
|
expr.space(),
|
2021-03-18 00:00:56 +00:00
|
|
|
match<Null>(op).space() as Parser<num>,
|
2021-03-17 23:04:36 +00:00
|
|
|
expr.space(),
|
2021-03-18 00:00:56 +00:00
|
|
|
]).map((r) => f(r.value![0], r.value![2])),
|
2021-03-17 23:04:36 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
registerBinary('**', (a, b) => pow(a, b));
|
|
|
|
registerBinary('*', (a, b) => a * b);
|
|
|
|
registerBinary('/', (a, b) => a / b);
|
|
|
|
registerBinary('%', (a, b) => a % b);
|
|
|
|
registerBinary('+', (a, b) => a + b);
|
|
|
|
registerBinary('-', (a, b) => a - b);
|
|
|
|
registerBinary('^', (a, b) => a.toInt() ^ b.toInt());
|
|
|
|
registerBinary('&', (a, b) => a.toInt() & b.toInt());
|
|
|
|
registerBinary('|', (a, b) => a.toInt() | b.toInt());
|
|
|
|
|
|
|
|
alternatives.addAll([
|
|
|
|
number,
|
|
|
|
hex,
|
|
|
|
binary,
|
|
|
|
expr.parenthesized(),
|
|
|
|
]);
|
|
|
|
|
|
|
|
expr.parser = longest(alternatives);
|
|
|
|
|
|
|
|
return expr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
var calculator = calculatorGrammar();
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
stdout.write('Enter an expression: ');
|
2021-03-18 00:00:56 +00:00
|
|
|
var line = stdin.readLineSync()!;
|
2021-03-17 23:04:36 +00:00
|
|
|
var scanner = new SpanScanner(line, sourceUrl: 'stdin');
|
2021-03-18 00:00:56 +00:00
|
|
|
var result = calculator.parse(scanner)!;
|
2021-03-17 23:04:36 +00:00
|
|
|
|
|
|
|
if (!result.successful) {
|
|
|
|
for (var error in result.errors) {
|
|
|
|
stderr.writeln(error.toolString);
|
2021-03-18 00:00:56 +00:00
|
|
|
stderr.writeln(error.span!.highlight(color: true));
|
2021-03-17 23:04:36 +00:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
print(result.value);
|
|
|
|
}
|
|
|
|
}
|