mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-10 03:13:46 +00:00
Estimated hours taken: 1 Fix some problems in the samples. samples/calculator.m: Strip spaces from the input before using it. I keep forgetting that spaces aren't allowed in the input of this example, and I can only assume that new users get confused over this. samples/c_interface/c_calls_mercury/Mmakefile: Use MLOBJS instead of MLLIBS for including .o files. Add a missing dependency. Remove an unnecessary dependency that MLOBJS takes care of. samples/c_interface/mercury_calls_fortran/Mmakefile: Use MLOBJS instead of MLLIBS for including .o files. Use -lg2c instead of the old -lf2c for the fortran library. (libf2c no longer exists)
110 lines
2.7 KiB
Mathematica
110 lines
2.7 KiB
Mathematica
% A simpler calculator - parses and evaluates integer expressions.
|
|
|
|
% For an example of a parser with better error handling, see parser.m in
|
|
% the Mercury library source code.
|
|
|
|
% Author: fjh.
|
|
|
|
% This source file is hereby placed in the public domain. -fjh.
|
|
|
|
:- module calculator.
|
|
:- interface.
|
|
:- import_module io.
|
|
|
|
:- pred main(io__state::di, io__state::uo) is det.
|
|
|
|
:- implementation.
|
|
:- import_module list, char, int, string.
|
|
|
|
:- type expr
|
|
---> number(int)
|
|
; plus(expr, expr)
|
|
; minus(expr, expr)
|
|
; times(expr, expr)
|
|
; div(expr, expr).
|
|
|
|
main -->
|
|
io__write_string("calculator> "),
|
|
io__flush_output,
|
|
io__read_line(Res),
|
|
( { Res = error(_) },
|
|
io__write_string("Error reading from stdin\n")
|
|
; { Res = eof },
|
|
io__write_string("EOF\n")
|
|
; { Res = ok(Line0) },
|
|
{ list__delete_all(Line0, ' ', Line) },
|
|
( { fullexpr(X,Line,[]) } ->
|
|
{ Num = evalexpr(X) },
|
|
io__write_int(Num),
|
|
io__write_string("\n")
|
|
;
|
|
io__write_string("Syntax error\n")
|
|
),
|
|
main % recursively call ourself for the next line(s)
|
|
).
|
|
|
|
:- func evalexpr(expr) = int.
|
|
evalexpr(number(Num)) = Num.
|
|
evalexpr(plus(X,Y)) = evalexpr(X) + evalexpr(Y).
|
|
evalexpr(minus(X,Y)) = evalexpr(X) - evalexpr(Y).
|
|
evalexpr(times(X,Y)) = evalexpr(X) * evalexpr(Y).
|
|
evalexpr(div(X,Y)) = evalexpr(X) // evalexpr(Y).
|
|
|
|
% Simple recursive-descent parser.
|
|
|
|
:- pred fullexpr(expr::out, list(char)::in, list(char)::out) is semidet.
|
|
fullexpr(X) -->
|
|
expr(X),
|
|
['\n'].
|
|
|
|
:- pred expr(expr::out, list(char)::in, list(char)::out) is semidet.
|
|
expr(Expr) -->
|
|
factor(Factor),
|
|
expr2(Factor, Expr).
|
|
|
|
:- pred expr2(expr::in, expr::out, list(char)::in, list(char)::out) is semidet.
|
|
expr2(Factor, Expr) -->
|
|
( ['+'] -> factor(Factor2), expr2(plus( Factor, Factor2), Expr)
|
|
; ['-'] -> factor(Factor2), expr2(minus(Factor, Factor2), Expr)
|
|
; { Expr = Factor }
|
|
).
|
|
|
|
:- pred factor(expr::out, list(char)::in, list(char)::out) is semidet.
|
|
factor(Factor) -->
|
|
term(Term),
|
|
factor2(Term, Factor).
|
|
|
|
:- pred factor2(expr::in, expr::out, list(char)::in, list(char)::out)
|
|
is semidet.
|
|
factor2(Term, Factor) -->
|
|
( ['*'] -> term(Term2), factor2(times(Term,Term2), Factor)
|
|
; ['/'] -> term(Term2), factor2(div( Term,Term2), Factor)
|
|
; { Factor = Term }
|
|
).
|
|
|
|
:- pred term(expr::out, list(char)::in, list(char)::out) is semidet.
|
|
term(Term) -->
|
|
( const(Const) ->
|
|
{ string__from_char_list(Const, ConstString) },
|
|
{ string__to_int(ConstString, Num) },
|
|
{ Term = number(Num) }
|
|
;
|
|
['('], expr(Term), [')']
|
|
).
|
|
|
|
:- pred const(list(char)::out, list(char)::in, list(char)::out) is semidet.
|
|
const([Digit|Rest]) -->
|
|
digit(Digit),
|
|
( const(Const) ->
|
|
{ Rest = Const }
|
|
;
|
|
{ Rest = [] }
|
|
).
|
|
|
|
:- pred digit(char::out, list(char)::in, list(char)::out) is semidet.
|
|
digit(Char) -->
|
|
[Char],
|
|
{ char__is_digit(Char) }.
|
|
|
|
|