Reputation: 21855
I'm writing a simple calculator in SML , and my code need to support 3 kinds of parentheses :
( )
[ ]
{ }
Where inside { }
, can appear { } , [ ] , ( )
expressions ,
Inside [ ]
, can appear [ ] , ( )
expressions ,
And inside ( )
, can appear only ( )
expressions .
Meaning is , that { }
has the highest priority , the [ ]
- the middle priority , and ( )
has the lowest priority .
What would be the best approach for accomplishing that ?
I've written a big method with too much loops and recursions that runs on separate cases , but I don't think this is the best approach .
Any suggestions would be greatly appreciated
Regards
EDIT :
The relevant code :
signature CalculatorOperation = sig
datatype token =
(* paranthesis *)
Lpar3 (* { *)
| Rpar3 (* } *)
| Lpar2 (* [ *)
| Rpar2 (* ] *)
| Lpar (* ( *)
| Rpar (* ) *)
the structure :
structure CalculatorOperation : CalculatorOperation = struct
datatype token =
(* paranthesis *)
Lpar3 (* { *)
| Rpar3 (* } *)
| Lpar2 (* [ *)
| Rpar2 (* ] *)
| Lpar (* ( *)
| Rpar (* ) *)
Scanner :
fun stringScanner s [] = (toToken s,[])
| stringScanner s (c::l)
= case c::l of
#" "::r => if s = "" then (stringScanner "" l) else (toToken s,l)
(* paranthesis *)
| #"{"::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)
Parser :
structure CalculatorParser : CalculatorParser = struct
open CalculatorOperation
exception CalculatorParser
datatype expr = NumNode of int
| UminusNode of expr
| MultiplyNode of expr * expr
| DivNode of expr * expr
| PlusNode of expr * expr
| MinusNode of expr * expr
| ModuloNode of expr * expr
| PowerNode of expr * expr
fun parserBrackets l = parserHelper2 l
and parserHelper l
= case l of
(Num n)::l1 => (NumNode n,l1)
| Lpar3::l1 => let val (en,l2) = parserBrackets l1 in case l2 of Rpar3::l3 => (en,l3)
| _ => raise CalculatorParser end
| Lpar2::l1 => let val (en,l2) = parserBrackets l1 in case l2 of Rpar2::l3 => (en,l3)
| _ => raise CalculatorParser end
| Lpar::l1 => let val (en,l2) = parserBrackets l1 in case l2 of Rpar::l3 => (en,l3)
| _ => raise CalculatorParser end
Upvotes: 3
Views: 450
Reputation: 837
I am not an SML expert, but from your description I gather that the syntactical rules you are looking for could be expressed in BNF as follows:
<expr1> ::= '{' ( <expr1> | <expr2> ) '}'
<expr2> ::= '[' ( <expr2> | <expr3> ) ']'
<expr3> ::= '(' ( <expr3> | <expr> ) ')'
When I look at your definition of the datatype expr it seems to me that you could define similar types for expr1, expr2 and expr3 as follows:
datatype expr3 = E3Node of expr3
| ENode of expr
datatype expr2 = E2Node of expr2
| E3Node of expr3
datatype expr1 = E1Node of expr1
| E2Node of expr2
Honestly, I don't even know if this is valid SML, but I am sure you would be able to fix that ... and fill in the gaps.
Upvotes: 2