Search code examples
parsingsmlsmlnj

Trying to set unmatched parenthesis as incorrect input , doesn't work in SML


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 ?


Solution

  • 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