1 # -*-mode: tcl; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
3 # $Id: Parse.tcl,v 1.8 2009-03-27 00:14:45 villate Exp $
5 ###### Parse.tcl ######
6 ############################################################
7 # Netmath Copyright (C) 1998 William F. Schelter #
8 # For distribution under GNU public License. See COPYING. #
9 ############################################################
11 global Parser parse_table
12 if {[info exists Parser
]} {catch { unset Parser
}}
14 foreach v
{ { ( 120 } { \[ 120 } { ) 120 } { \] 120 } { ^
110}
15 { ^
- 110} {* 100} { / 100} {% 100} {- 90 } { + 90 }
16 { << 80} { >> 80 } { < 70 } { > 70 } { <= 70 } {>= 70}
17 { == 60 } { & 50} { |
40 } { , 40 } {= 40}
18 { && 30 } { ||
20 } { ?
10 } { : 10 } { ; 5 }} {
19 set parse_table
([lindex $v 0]) [lindex $v 1]
20 set getOp
([lindex $v 0]) doBinary
24 proc binding_power
{s
} {
25 global parse_table billy
27 if { [catch { set tem
$parse_table($s) }] } {
34 proc getOneMatch
{ s inds
} {
35 return [string range
$s [lindex $inds 0] [lindex $inds 1]]
38 proc parseTokenize
{ str
} {
39 regsub -all {[*][*]} $str "^" str
41 while { [string length
$str ] > 0 } {
42 # puts "ans=$ans,str=$str"
43 set str
[string trimleft
$str " \t\n" ]
44 set s
[string range
$str 0 1]
45 set bp
[binding_power
$s]
48 set str
[string range
$str 2 end
]
51 set s
[string range
$s 0 0]
52 set bp
[binding_power
$s]
55 set str
[string range
$str 1 end
]
62 if { [regexp -indices {^
[0-9.
]+([eE
][+---]?
[0-9]+)?
} $str all
] } {
63 append ans
" { number [getOneMatch $str $all] }"
64 # append ans " [getOneMatch $str $all]"
65 set str
[string range
$str [expr {1+ [lindex $all 1]}] end
]
66 } elseif
{ [regexp -indices {^
[$a-zA
-Z
][a-zA-Z0-9
]*} $str all
] } {
67 append ans
" { id [getOneMatch $str $all] } "
68 # append ans " [getOneMatch $str $all]"
69 set str
[string range
$str [expr {1+ [lindex $all 1]}] end
]
71 error [concat [mc
"parser unrecognized:"] "$str"]
77 set Parser
(reserved
) " acos cos hypo sinh asin cosh log sqrt atan exp log10 tan atan2 floor pow tanh ceil fmod sin abs double int round"
79 set Parser
(help
) [join [list [mc
\
81 The syntax
for the definition of functions is like C
, except that it is
\
82 permitted to write x^n instead of pow
(x
,n
).
84 Functions
:}] $Parser(reserved
) [mc
{
86 Operators
:}] " == % & || ( << <= ) : * >= + && , | < >> - > ^ ? /" ] ""]
92 set x
[lindex $Parser(tokenlist
) [incr Parser
(tokenind
) ]]
94 if {[llength $x ] > 1 } {
95 set Parser
(tokenval
) [lindex $x 1]
104 #-----------------------------------------------------------------
106 # parseToSuffixLists -- Convert EXPR1; EXPR2; ..
107 # to a list of suffix lists. Each suffix list is suitable for
108 # evaluating on a stack machine (like postscript) or for converting
109 # further into another form. see parseFromSuffixList.
111 # {number 1} {number 2} + {number 3} {number 4} ^ -
112 # Results: suffix list form of the original EXPR
116 #----------------------------------------------------------------
118 proc parseToSuffixLists
{ a
} {
120 set Parser
(result
) ""
121 set Parser
(tokenlist
) [parseTokenize
$a]
122 set Parser
(tokenind
) -1
123 set Parser
(lookahead
) [nexttok
]
124 #puts tokenlist=$Parser(tokenlist)
126 while { "$Parser(lookahead)" != "" } {
127 getExpr
; parseMatch
";"
128 #puts "here: $Parser(result) "
129 append ans
"[list $Parser(result)] "
130 set Parser
(result
) ""
132 regsub \\^
- $ans {PRE_MINUS ^
} ans2
136 proc parseMatch
{ t
} {
138 if { "$t" == "$Parser(lookahead)" } {
139 set Parser
(lookahead
) [nexttok
]
141 error "syntax error: wanted $t"
145 proc emit
{ s args
} {
147 if { "$args" == "" } {
148 append Parser
(result
) " $s"
151 append Parser
(result
) " {[lindex $args 0 ] $s}"
152 #puts " {[lindex $args 0 ] $s} "
160 proc getExprn
{ n
} {
162 #puts "getExpr $n, $Parser(tokenind),$Parser(tokenlist)"
170 if { "$Parser(lookahead)" == "-" ||
"$Parser(lookahead)" == "+" } {
171 if { "$Parser(lookahead)" == "-" } {
176 parseMatch
$Parser(lookahead
)
178 #puts "l=$Parser(lookahead),pl=$Parser(result)"
187 if { [binding_power
$Parser(lookahead
)] == $n } {
188 set this
$Parser(lookahead
)
189 parseMatch
$Parser(lookahead
)
193 while { "$this" == "^" && "$Parser(lookahead)" == "^" } {
194 # puts "p=$Parser(result),$
195 set this
$Parser(lookahead
)
196 append toemit
" $this"
197 parseMatch
$Parser(lookahead
)
200 foreach v
$toemit { emit
$v }
210 proc getExpr120
{ } {
212 #puts "getExpr120, $Parser(tokenind),[lrange $Parser(tokenlist) $Parser(tokenind) end]"
214 if { "$Parser(lookahead)" == "(" } {
215 parseMatch
$Parser(lookahead
)
219 } elseif
{ $Parser(lookahead
) == "id" } {
220 emit
$Parser(tokenval
) id
222 parseMatch
$Parser(lookahead
)
223 if { "$Parser(lookahead)" == "(" } {
228 } elseif
{ $Parser(lookahead
) == "number" } {
229 emit
$Parser(tokenval
) number
230 parseMatch
$Parser(lookahead
)
233 bgerror [mc
"syntax error"]
240 set getOp
(PRE_PLUS
) doPrefix
241 set getOp
(PRE_MINUS
) doPrefix
242 set getOp
(funcall
) doFuncall
244 set getOp
(:) doConditional
245 set getOp
(?
) doConditional
248 uplevel 1 {set s
$nargs; incr nargs
-1 ;
250 set a
($nargs) "$a($nargs) $x $a($s)"
252 set a
($nargs) "($a($nargs) $x $a($s))"}
257 uplevel 1 {set s
$nargs; incr nargs
-1 ; set a
($nargs) "pow($a($nargs),$a($s))" }
263 set s
$nargs; incr nargs
-1 ; set a
($nargs) "$a($nargs)($a($s))"
268 uplevel 1 { if { "$x" == "PRE_MINUS" } { set a
($nargs) "-$a($nargs)" } }
271 proc doConditional
{ } {
272 set x
[uplevel 1 set x
]
273 if { "$x" == "?" } { return }
276 set s
$nargs ; incr nargs
-2 ;
277 set a
($nargs) "($a($nargs) ? $a([expr {$nargs + 1}]) : $a($s))"
283 #-----------------------------------------------------------------
285 # parseFromSuffixList -- takes a token list, and turns
286 # it into a suffix form. eg: 1 + 2 - 3 ^ 4 --> 1 2 + 3 4 ^ -
291 #----------------------------------------------------------------
293 proc parseFromSuffixList
{ list } {
296 set lim
[llength $list]
299 while { $i < $lim } {
300 set x
[lindex $list $i ]
301 set bp
[binding_power
$x]
304 if { [llength $x] > 1 } {
306 set a
([incr nargs
]) [lindex $x 1]
318 #-----------------------------------------------------------------
320 # parseConvert -- given an EXPRESSION, parse it and find out
321 # what are the variables, and convert a^b to pow(a,b). If
322 # -variables "x y" is given, then x and y will be replaced by $x $y
328 #----------------------------------------------------------------
331 set Parser
(convertOptions
) {
332 { doall
0 "convert all variables x to \$x" }
333 { variables
"" "list of variables to change from x to \$x" }
335 proc parseConvert
{ expr args
} {
337 getOptions
$Parser(convertOptions
) $args
338 if { "$expr" == "" } { return [list {} {}] }
339 set parselist
[parseToSuffixLists
"$expr;"]
340 #puts "parselist=$parselist"
341 catch { unset allvars
}
344 foreach lis
$parselist {
348 if { ("[lindex $v 0]" == "id")
349 && ([llength $v] == 2)
350 && ([lsearch $Parser(reserved
) [set w
[lindex $v 1]]] < 0)
352 if { ($doall != 0) ||
([lsearch $variables $w] >= 0) } {
353 append new
" {id \$$w}"
360 if { [llength $v] > 1 } {
367 append answers
"[list [parseFromSuffixList $new]] "
370 return [list $answers [array names allvars
]]
374 set me
[parseFromSuffixList
[lindex [parseToSuffixLists
"$s;"] 0]]
376 return "[eval expr $s] [eval expr $me]"
382 ## endsource parse.tcl