Reputation: 1978
This is the code I am using to separate a string into variables and operators. So that they can be operated upon.
String expression = "1567x356-234+908/56x12"; int lastPos = 0;
List<double> exprVar = new List<double>();
List<String> operator = new List<String>();
for (int i =0; i < expression.length; i++) {
if (expression[i] == "+" || expression[i] == "-" || expression[i] == "/" || expression[i] == "x") {
operator.add(expression[i]);
exprVar.add(double.parse(expression.substring(lastPos, i)));
lastPos = i+1;
}
if (i == expression.length - 1) {
exprVar.add(double.parse(expression.substring(lastPos, i+1)));
}
}
print("The Numbers are is: $exprVar");
print("The operators are: $operator");
I have two questions:
Am I reinventing the wheel here? Is there a String library function in dart that I am unaware of that might make this code more convenient?
Now that I have the numbers and operator, do I have to write code to determine the order of precedence of operators or can I make a giant single line expression and the processor would solve it for me?
Upvotes: 5
Views: 7030
Reputation: 11210
An example of how to do this very simply.
You can check how it works in DartPad.
Dart calculator generated by PEG generator. https://pub.dev/packages/peg
You can also generate a parser, just the way you need it.
Grammar from which a parser of 500 lines of code is generated.
Completely ready for work.
Completely ready for modification.
The grammar includes (in its definition) a small example of using the parser.
More information can be found here.
https://pub.dev/packages/peg
https://github.com/mezoni/peg
%{
// ignore_for_file: prefer_final_locals
import 'package:source_span/source_span.dart';
void main() {
const source = ' 1 + 2 * 3 + x ';
final result = calc(source, {'x': 5});
print(result);
}
int calc(String source, Map<String, int> vars) {
final parser = CalcParser(vars);
final state = State(source);
final result = parser.parseStart(state);
if (result == null) {
final file = SourceFile.fromString(source);
throw FormatException(state
.getErrors()
.map((e) => file.span(e.start, e.end).message(e.message))
.join('\n'));
}
return result.$1;
}
}%
%%
Map<String, int> vars = {};
CalcParser(this.vars);
%%
`int`
Start =>
S
$ = Expr
EOF
`int`
Expr('expression') =>
Sum
`int`
Sum =>
$ = Product
@while (*) {
[+] S
r = Product
{ $ += r; }
----
[-] S
r = Product
{ $ -= r; }
}
`int`
Product =>
$ = Value
@while (*) {
[*] S
r = Value
{ $ *= r; }
----
[/] S
r = Value
{ $ ~/= r; }
}
`int`
Value('expression') => (
NUMBER
----
i = ID
$ = { $$ = vars[i]!; }
----
'(' S
$ = Expr
')' S
)
`int`
NUMBER =>
n = <[0-9]+>
S
$ = { $$ = int.parse(n); }
`String`
ID =>
$ = <[a-zA-Z]>
S
`void`
EOF('end of file') =>
! .
`void`
S => [ \t\r\n]*
Automatic generation of common errors is also supported.
Input: ''
----------------------------------------
FormatException: line 1, column 1: Expected: 'expression'
╷
1 │
│ ^
╵
========================================
Input: '1`'
----------------------------------------
FormatException: line 1, column 2: Expected: 'end of file'
╷
1 │ 1`
│ ^
╵
========================================
Input: '1+'
----------------------------------------
FormatException: line 1, column 3: Expected: 'expression'
╷
1 │ 1+
│ ^
╵
========================================
Input: '(1+'
----------------------------------------
FormatException: line 1, column 4: Expected: 'expression'
╷
1 │ (1+
│ ^
╵
========================================
Input: '(1'
----------------------------------------
FormatException: line 1, column 3: Expected: ')'
╷
1 │ (1
│ ^
╵
========================================
Script for examine error messages.
import 'package:source_span/source_span.dart';
import 'example.dart';
void main(List<String> args) {
final strings = ['', '1`', '1+', '(1+', '(1'];
for (final element in strings) {
print('Input: \'$element\'');
print('-' * 40);
try {
parse(element);
} catch (e) {
print(e);
print('=' * 40);
}
}
}
int parse(String source) {
final parser = CalcParser(const {});
final state = State(source);
final result = parser.parseStart(state);
if (!state.isSuccess) {
final file = SourceFile.fromString(source);
throw FormatException(state
.getErrors()
.map((e) => file.span(e.start, e.end).message(e.message))
.join('\n'));
}
return result as int;
}
Upvotes: 0
Reputation: 11
you can use tiny_expr
package, there is simple and straightforward implementation of parsing the expressions from string.
Upvotes: 1
Reputation: 5742
use function_tree
see documentation https://pub.dev/packages/function_tree#-installing-tab-
final expressionsExample = [
'2 + 2 - 2 - 2',
'(3 + 2)^3',
'3 * pi / 4',
'3 * sin(5 * pi / 6)',
'e^(-1)'
];
for (final expression in expressionsExample) {
print("'$expression' -> ${expression.interpret()}");
}
Output will be
'2 + 2 - 2 - 2' -> 0
'(3 + 2)^3' -> 125
'3 * pi / 4' -> 2.356194490192345
'3 * sin(5 * pi / 6)' -> 1.5000000000000009
'e^(-1)' -> 0.36787944117144233
Upvotes: 11