|  | #!/usr/bin/tclsh | 
|  | # | 
|  | # Generate the file opcodes.h. | 
|  | # | 
|  | # This TCL script scans a concatenation of the parse.h output file from the | 
|  | # parser and the vdbe.c source file in order to generate the opcodes numbers | 
|  | # for all opcodes. | 
|  | # | 
|  | # The lines of the vdbe.c that we are interested in are of the form: | 
|  | # | 
|  | #       case OP_aaaa:      /* same as TK_bbbbb */ | 
|  | # | 
|  | # The TK_ comment is optional.  If it is present, then the value assigned to | 
|  | # the OP_ is the same as the TK_ value.  If missing, the OP_ value is assigned | 
|  | # a small integer that is different from every other OP_ value. | 
|  | # | 
|  | # We go to the trouble of making some OP_ values the same as TK_ values | 
|  | # as an optimization.  During parsing, things like expression operators | 
|  | # are coded with TK_ values such as TK_ADD, TK_DIVIDE, and so forth.  Later | 
|  | # during code generation, we need to generate corresponding opcodes like | 
|  | # OP_Add and OP_Divide.  By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide, | 
|  | # code to translate from one to the other is avoided.  This makes the | 
|  | # code generator smaller and faster. | 
|  | # | 
|  | # This script also scans for lines of the form: | 
|  | # | 
|  | #       case OP_aaaa:       /* jump, in1, in2, in3, out2-prerelease, out3 */ | 
|  | # | 
|  | # When such comments are found on an opcode, it means that certain | 
|  | # properties apply to that opcode.  Set corresponding flags using the | 
|  | # OPFLG_INITIALIZER macro. | 
|  | # | 
|  |  | 
|  | set in stdin | 
|  | set currentOp {} | 
|  | set nOp 0 | 
|  | while {![eof $in]} { | 
|  | set line [gets $in] | 
|  |  | 
|  | # Remember the TK_ values from the parse.h file. | 
|  | # NB:  The "TK_" prefix stands for "ToKen", not the graphical Tk toolkit | 
|  | # commonly associated with TCL. | 
|  | # | 
|  | if {[regexp {^#define TK_} $line]} { | 
|  | set tk([lindex $line 1]) [lindex $line 2] | 
|  | continue | 
|  | } | 
|  |  | 
|  | # Find "/* Opcode: " lines in the vdbe.c file.  Each one introduces | 
|  | # a new opcode.  Remember which parameters are used. | 
|  | # | 
|  | if {[regexp {^.. Opcode: } $line]} { | 
|  | set currentOp OP_[lindex $line 2] | 
|  | set m 0 | 
|  | foreach term $line { | 
|  | switch $term { | 
|  | P1 {incr m 1} | 
|  | P2 {incr m 2} | 
|  | P3 {incr m 4} | 
|  | P4 {incr m 8} | 
|  | P5 {incr m 16} | 
|  | } | 
|  | } | 
|  | set paramused($currentOp) $m | 
|  | } | 
|  |  | 
|  | # Find "** Synopsis: " lines that follow Opcode: | 
|  | # | 
|  | if {[regexp {^.. Synopsis: (.*)} $line all x] && $currentOp!=""} { | 
|  | set synopsis($currentOp) [string trim $x] | 
|  | } | 
|  |  | 
|  | # Scan for "case OP_aaaa:" lines in the vdbe.c file | 
|  | # | 
|  | if {[regexp {^case OP_} $line]} { | 
|  | set line [split $line] | 
|  | set name [string trim [lindex $line 1] :] | 
|  | set op($name) -1 | 
|  | set jump($name) 0 | 
|  | set in1($name) 0 | 
|  | set in2($name) 0 | 
|  | set in3($name) 0 | 
|  | set out2($name) 0 | 
|  | set out3($name) 0 | 
|  | for {set i 3} {$i<[llength $line]-1} {incr i} { | 
|  | switch [string trim [lindex $line $i] ,] { | 
|  | same { | 
|  | incr i | 
|  | if {[lindex $line $i]=="as"} { | 
|  | incr i | 
|  | set sym [string trim [lindex $line $i] ,] | 
|  | set val $tk($sym) | 
|  | set op($name) $val | 
|  | set used($val) 1 | 
|  | set sameas($val) $sym | 
|  | set def($val) $name | 
|  | } | 
|  | } | 
|  | jump {set jump($name) 1} | 
|  | in1  {set in1($name) 1} | 
|  | in2  {set in2($name) 1} | 
|  | in3  {set in3($name) 1} | 
|  | out2 {set out2($name) 1} | 
|  | out3 {set out3($name) 1} | 
|  | } | 
|  | } | 
|  | set order($nOp) $name | 
|  | incr nOp | 
|  | } | 
|  | } | 
|  |  | 
|  | # Assign numbers to all opcodes and output the result. | 
|  | # | 
|  | puts "/* Automatically generated.  Do not edit */" | 
|  | puts "/* See the tool/mkopcodeh.tcl script for details */" | 
|  | foreach name {OP_Noop OP_Explain} { | 
|  | set jump($name) 0 | 
|  | set in1($name) 0 | 
|  | set in2($name) 0 | 
|  | set in3($name) 0 | 
|  | set out2($name) 0 | 
|  | set out3($name) 0 | 
|  | set op($name) -1 | 
|  | set order($nOp) $name | 
|  | incr nOp | 
|  | } | 
|  |  | 
|  | # The following are the opcodes that are processed by resolveP2Values() | 
|  | # | 
|  | set rp2v_ops { | 
|  | OP_Transaction | 
|  | OP_AutoCommit | 
|  | OP_Savepoint | 
|  | OP_Checkpoint | 
|  | OP_Vacuum | 
|  | OP_JournalMode | 
|  | OP_VUpdate | 
|  | OP_VFilter | 
|  | OP_Next | 
|  | OP_NextIfOpen | 
|  | OP_SorterNext | 
|  | OP_Prev | 
|  | OP_PrevIfOpen | 
|  | } | 
|  |  | 
|  | # Assign small values to opcodes that are processed by resolveP2Values() | 
|  | # to make code generation for the switch() statement smaller and faster. | 
|  | # | 
|  | set cnt -1 | 
|  | for {set i 0} {$i<$nOp} {incr i} { | 
|  | set name $order($i) | 
|  | if {[lsearch $rp2v_ops $name]>=0} { | 
|  | incr cnt | 
|  | while {[info exists used($cnt)]} {incr cnt} | 
|  | set op($name) $cnt | 
|  | set used($cnt) 1 | 
|  | set def($cnt) $name | 
|  | } | 
|  | } | 
|  |  | 
|  | # Assign the next group of values to JUMP opcodes | 
|  | # | 
|  | for {set i 0} {$i<$nOp} {incr i} { | 
|  | set name $order($i) | 
|  | if {$op($name)>=0} continue | 
|  | if {!$jump($name)} continue | 
|  | incr cnt | 
|  | while {[info exists used($cnt)]} {incr cnt} | 
|  | set op($name) $cnt | 
|  | set used($cnt) 1 | 
|  | set def($cnt) $name | 
|  | } | 
|  |  | 
|  | # Find the numeric value for the largest JUMP opcode | 
|  | # | 
|  | set mxJump -1 | 
|  | for {set i 0} {$i<$nOp} {incr i} { | 
|  | set name $order($i) | 
|  | if {$jump($name) && $op($name)>$mxJump} {set mxJump $op($name)} | 
|  | } | 
|  |  | 
|  |  | 
|  | # Generate the numeric values for all remaining opcodes | 
|  | # | 
|  | for {set i 0} {$i<$nOp} {incr i} { | 
|  | set name $order($i) | 
|  | if {$op($name)<0} { | 
|  | incr cnt | 
|  | while {[info exists used($cnt)]} {incr cnt} | 
|  | set op($name) $cnt | 
|  | set used($cnt) 1 | 
|  | set def($cnt) $name | 
|  | } | 
|  | } | 
|  | set max $cnt | 
|  | for {set i 0} {$i<$nOp} {incr i} { | 
|  | if {![info exists used($i)]} { | 
|  | set def($i) "OP_NotUsed_$i" | 
|  | } | 
|  | set name $def($i) | 
|  | puts -nonewline [format {#define %-16s %3d} $name $i] | 
|  | set com {} | 
|  | if {[info exists sameas($i)]} { | 
|  | set com "same as $sameas($i)" | 
|  | } | 
|  | if {[info exists synopsis($name)]} { | 
|  | set x $synopsis($name) | 
|  | if {$com==""} { | 
|  | set com "synopsis: $x" | 
|  | } else { | 
|  | append com ", synopsis: $x" | 
|  | } | 
|  | } | 
|  | if {$com!=""} { | 
|  | puts -nonewline [format " /* %-42s */" $com] | 
|  | } | 
|  | puts "" | 
|  | } | 
|  |  | 
|  | # Generate the bitvectors: | 
|  | # | 
|  | set bv(0) 0 | 
|  | for {set i 0} {$i<=$max} {incr i} { | 
|  | set name $def($i) | 
|  | set x 0 | 
|  | if {$jump($name)}  {incr x 1} | 
|  | if {$in1($name)}   {incr x 2} | 
|  | if {$in2($name)}   {incr x 4} | 
|  | if {$in3($name)}   {incr x 8} | 
|  | if {$out2($name)}  {incr x 16} | 
|  | if {$out3($name)}  {incr x 32} | 
|  | set bv($i) $x | 
|  | } | 
|  | puts "" | 
|  | puts "/* Properties such as \"out2\" or \"jump\" that are specified in" | 
|  | puts "** comments following the \"case\" for each opcode in the vdbe.c" | 
|  | puts "** are encoded into bitvectors as follows:" | 
|  | puts "*/" | 
|  | puts "#define OPFLG_JUMP        0x01  /* jump:  P2 holds jmp target */" | 
|  | puts "#define OPFLG_IN1         0x02  /* in1:   P1 is an input */" | 
|  | puts "#define OPFLG_IN2         0x04  /* in2:   P2 is an input */" | 
|  | puts "#define OPFLG_IN3         0x08  /* in3:   P3 is an input */" | 
|  | puts "#define OPFLG_OUT2        0x10  /* out2:  P2 is an output */" | 
|  | puts "#define OPFLG_OUT3        0x20  /* out3:  P3 is an output */" | 
|  | puts "#define OPFLG_INITIALIZER \173\\" | 
|  | for {set i 0} {$i<=$max} {incr i} { | 
|  | if {$i%8==0} { | 
|  | puts -nonewline [format "/* %3d */" $i] | 
|  | } | 
|  | puts -nonewline [format " 0x%02x," $bv($i)] | 
|  | if {$i%8==7} { | 
|  | puts "\\" | 
|  | } | 
|  | } | 
|  | puts "\175" | 
|  | puts "" | 
|  | puts "/* The sqlite3P2Values() routine is able to run faster if it knows" | 
|  | puts "** the value of the largest JUMP opcode.  The smaller the maximum" | 
|  | puts "** JUMP opcode the better, so the mkopcodeh.tcl script that" | 
|  | puts "** generated this include file strives to group all JUMP opcodes" | 
|  | puts "** together near the beginning of the list." | 
|  | puts "*/" | 
|  | puts "#define SQLITE_MX_JUMP_OPCODE  $mxJump  /* Maximum JUMP opcode */" |