import 'dart:math'; import 'dart:io'; import 'package:belatuk_combinator/belatuk_combinator.dart'; import 'package:string_scanner/string_scanner.dart'; /// Note: This grammar does not handle precedence, for the sake of simplicity. Parser calculatorGrammar() { var expr = reference(); var number = match(RegExp(r'-?[0-9]+(\.[0-9]+)?')) .value((r) => num.parse(r.span!.text)); var hex = match(RegExp(r'0x([A-Fa-f0-9]+)')) .map((r) => int.parse(r.scanner.lastMatch![1]!, radix: 16)); var binary = match(RegExp(r'([0-1]+)b')) .map((r) => int.parse(r.scanner.lastMatch![1]!, radix: 2)); var alternatives = >[]; void registerBinary(String op, num Function(num, num) f) { alternatives.add( chain([ expr.space(), match(op).space() as Parser, expr.space(), ]).map((r) => f(r.value![0], r.value![2])), ); } 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: '); var line = stdin.readLineSync()!; var scanner = SpanScanner(line, sourceUrl: 'stdin'); var result = calculator.parse(scanner); if (!result.successful) { for (var error in result.errors) { stderr.writeln(error.toolString); stderr.writeln(error.span!.highlight(color: true)); } } else { print(result.value); } } }