I'm writing a calculator in SML .
In my program I work with the below parenthesis :
{ } (* highest priority *)
[ ] (* middle priority *)
( ) (* weakest priority *)
When user enters a string such as :
calc "1+(2*3)" (* that's ok *)
but those :
calc "1+[2*3)" (* Not Ok *)
calc "1+(2*3}" (* Not Ok *)
calc "1+{2*3]" (* Not Ok *)
are not , since the opened bracket does not match its closing bracket .
I tried to write that in SML , but it doesn't work . What I want do when the user enter
an expression with unbalanced parenthesis , is to return -1
or present error message
Here's the code :
signature ScannerForExp = sig
datatype token =
(* parenthesis *)
Lpar3 (* { *)
| Rpar3 (* } *)
| Lpar2 (* [ *)
| Rpar2 (* ] *)
| Lpar (* ( *)
| Rpar (* ) *)
(* operations *)
| Multiply (* * *)
| Div (* / *)
| Plus (* + *)
| Minus (* - *)
| Modulo (* % *)
| Power (* ^ *)
| Num of int (* [0-9]+ *)
| Undef of string (* undefined *)
val scanner : string -> (token list)
end;
| #"{"::r => if s = "" then (Lpar3,r) else (toToken s,c::l)
| #"}"::r => if s = "" then (Rpar3,r) else (toToken s,c::l)
| #"["::r => if s = "" then (Lpar2,r) else (toToken s,c::l)
| #"]"::r => if s = "" then (Rpar2,r) else (toToken s,c::l)
| #"("::r => if s = "" then (Lpar,r) else (toToken s,c::l)
| #")"::r => if s = "" then (Rpar,r) else (toToken s,c::l)
And this is the function that handle this :
fun E l = E2 l
and F l
= case l of
(Num n)::l1 => (NumNode n,l1)
| Lpar::l1 => let val (en,l2) = E l1 in case l2 of Rpar::l3 => (en,l3)
| Lpar2::l1 => let val (en,l2) = E l1 in case l2 of Rpar2::l3 => (en,l3)
| Lpar3::l1 => let val (en,l2) = E l1 in case l2 of Rpar3::l3 => (en,l3)
...
...
(* more code *)
But when I try to add a rule that consists of Lpar
with Lpar2
or Lpar
with Lpar3
:
fun E l = E2 l
and F l
= case l of
(Num n)::l1 => (NumNode n,l1)
| Lpar::l1 => let val (en,l2) = E l1 in case l2 of Rpar::l3 => (en,l3)
| Lpar2::l1 => let val (en,l2) = E l1 in case l2 of Rpar2::l3 => (en,l3)
| Lpar3::l1 => let val (en,l2) = E l1 in case l2 of Rpar3::l3 => (en,l3)
(* a ( with a ] *)
| Lpar::l1 => let val (en,l2) = E l1 in case l2 of Rpar2::l3 => raise exception
I get :
stdIn:5875.9-5903.34 Error: match redundant and nonexhaustive
How can I fix that ?
Your indentation is a bit off, but it looks like the code you've already got should raise a ParserForExp
exception when the parentheses don't match.
With your "new" code, the error happens because you have two Lpar::l1
cases, which makes one of them redundant.
I believe you need to move the mismatching parentheses cases:
| Lpar::l1 => let val (en,l2) = E l1 in
case l2 of Rpar::l3 => (en,l3)
| Rpar2::l3 => [raise mismatched parentheses]
| Rpar3::l3 => [raise mismatched parentheses]
| _ => raise ParserForExp
end