platform/packages/combinator/example/calculator.dart

71 lines
1.9 KiB
Dart
Raw Normal View History

2021-03-17 23:04:36 +00:00
import 'dart:math';
import 'dart:io';
2021-05-14 06:11:50 +00:00
import 'package:angel3_combinator/angel3_combinator.dart';
2021-03-17 23:04:36 +00:00
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>();
2021-05-14 06:11:50 +00:00
var number = match<num>(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
2021-05-14 06:11:50 +00:00
var hex = match<int>(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
2021-05-14 06:11:50 +00:00
var binary = match<int>(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-05-11 09:03:52 +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-05-14 06:11:50 +00:00
var scanner = SpanScanner(line, sourceUrl: 'stdin');
2021-05-02 04:12:43 +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);
}
}