1b15393b8Sdrh#!/usr/bin/tclsh 2b15393b8Sdrh# 3b15393b8Sdrh# Generate the file opcodes.h. 4b15393b8Sdrh# 5b15393b8Sdrh# This TCL script scans a concatenation of the parse.h output file from the 6b15393b8Sdrh# parser and the vdbe.c source file in order to generate the opcodes numbers 7b15393b8Sdrh# for all opcodes. 8b15393b8Sdrh# 9b15393b8Sdrh# The lines of the vdbe.c that we are interested in are of the form: 10b15393b8Sdrh# 11b15393b8Sdrh# case OP_aaaa: /* same as TK_bbbbb */ 12b15393b8Sdrh# 13b15393b8Sdrh# The TK_ comment is optional. If it is present, then the value assigned to 14b15393b8Sdrh# the OP_ is the same as the TK_ value. If missing, the OP_ value is assigned 15b15393b8Sdrh# a small integer that is different from every other OP_ value. 16b15393b8Sdrh# 17b15393b8Sdrh# We go to the trouble of making some OP_ values the same as TK_ values 18b15393b8Sdrh# as an optimization. During parsing, things like expression operators 19b15393b8Sdrh# are coded with TK_ values such as TK_ADD, TK_DIVIDE, and so forth. Later 20b15393b8Sdrh# during code generation, we need to generate corresponding opcodes like 21b15393b8Sdrh# OP_Add and OP_Divide. By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide, 22b15393b8Sdrh# code to translate from one to the other is avoided. This makes the 237cc84c2cSdrh# code generator smaller and faster. 24b15393b8Sdrh# 25b15393b8Sdrh# This script also scans for lines of the form: 26b15393b8Sdrh# 27758784d1Smistachkin# case OP_aaaa: /* jump, in1, in2, in3, out2, out3 */ 28b15393b8Sdrh# 29b15393b8Sdrh# When such comments are found on an opcode, it means that certain 30b15393b8Sdrh# properties apply to that opcode. Set corresponding flags using the 31b15393b8Sdrh# OPFLG_INITIALIZER macro. 32b15393b8Sdrh# 33b15393b8Sdrh 34b15393b8Sdrhset in stdin 35b15393b8Sdrhset currentOp {} 36758784d1Smistachkinset prevName {} 37b15393b8Sdrhset nOp 0 38758784d1Smistachkinset nGroup 0 39b15393b8Sdrhwhile {![eof $in]} { 40b15393b8Sdrh set line [gets $in] 41b15393b8Sdrh 42b15393b8Sdrh # Remember the TK_ values from the parse.h file. 43b15393b8Sdrh # NB: The "TK_" prefix stands for "ToKen", not the graphical Tk toolkit 44b15393b8Sdrh # commonly associated with TCL. 45b15393b8Sdrh # 46b15393b8Sdrh if {[regexp {^#define TK_} $line]} { 47b15393b8Sdrh set tk([lindex $line 1]) [lindex $line 2] 48b15393b8Sdrh continue 49b15393b8Sdrh } 50b15393b8Sdrh 51b15393b8Sdrh # Find "/* Opcode: " lines in the vdbe.c file. Each one introduces 52b15393b8Sdrh # a new opcode. Remember which parameters are used. 53b15393b8Sdrh # 54b15393b8Sdrh if {[regexp {^.. Opcode: } $line]} { 55b15393b8Sdrh set currentOp OP_[lindex $line 2] 56b15393b8Sdrh set m 0 57b15393b8Sdrh foreach term $line { 58b15393b8Sdrh switch $term { 59b15393b8Sdrh P1 {incr m 1} 60b15393b8Sdrh P2 {incr m 2} 61b15393b8Sdrh P3 {incr m 4} 62b15393b8Sdrh P4 {incr m 8} 63b15393b8Sdrh P5 {incr m 16} 64b15393b8Sdrh } 65b15393b8Sdrh } 66b15393b8Sdrh set paramused($currentOp) $m 67b15393b8Sdrh } 68b15393b8Sdrh 69b15393b8Sdrh # Find "** Synopsis: " lines that follow Opcode: 70b15393b8Sdrh # 71b15393b8Sdrh if {[regexp {^.. Synopsis: (.*)} $line all x] && $currentOp!=""} { 72b15393b8Sdrh set synopsis($currentOp) [string trim $x] 73b15393b8Sdrh } 74b15393b8Sdrh 75b15393b8Sdrh # Scan for "case OP_aaaa:" lines in the vdbe.c file 76b15393b8Sdrh # 77b15393b8Sdrh if {[regexp {^case OP_} $line]} { 78b15393b8Sdrh set line [split $line] 79b15393b8Sdrh set name [string trim [lindex $line 1] :] 804031bafaSdrh if {$name=="OP_Abortable"} continue; # put OP_Abortable last 81b15393b8Sdrh set op($name) -1 82758784d1Smistachkin set group($name) 0 83b15393b8Sdrh set jump($name) 0 84b15393b8Sdrh set in1($name) 0 85b15393b8Sdrh set in2($name) 0 86b15393b8Sdrh set in3($name) 0 87b15393b8Sdrh set out2($name) 0 88ed94af5eSdrh set out3($name) 0 89b15393b8Sdrh for {set i 3} {$i<[llength $line]-1} {incr i} { 90b15393b8Sdrh switch [string trim [lindex $line $i] ,] { 91b15393b8Sdrh same { 92b15393b8Sdrh incr i 93b15393b8Sdrh if {[lindex $line $i]=="as"} { 94b15393b8Sdrh incr i 95b15393b8Sdrh set sym [string trim [lindex $line $i] ,] 96b15393b8Sdrh set val $tk($sym) 97b15393b8Sdrh set op($name) $val 98b15393b8Sdrh set used($val) 1 99b15393b8Sdrh set sameas($val) $sym 100b15393b8Sdrh set def($val) $name 101b15393b8Sdrh } 102b15393b8Sdrh } 103758784d1Smistachkin group {set group($name) 1} 104b15393b8Sdrh jump {set jump($name) 1} 105b15393b8Sdrh in1 {set in1($name) 1} 106b15393b8Sdrh in2 {set in2($name) 1} 107b15393b8Sdrh in3 {set in3($name) 1} 108b15393b8Sdrh out2 {set out2($name) 1} 109b15393b8Sdrh out3 {set out3($name) 1} 110b15393b8Sdrh } 111b15393b8Sdrh } 112758784d1Smistachkin if {$group($name)} { 113758784d1Smistachkin set newGroup 0 114758784d1Smistachkin if {[info exists groups($nGroup)]} { 115758784d1Smistachkin if {$prevName=="" || !$group($prevName)} { 116758784d1Smistachkin set newGroup 1 117758784d1Smistachkin } 118758784d1Smistachkin } 119758784d1Smistachkin lappend groups($nGroup) $name 120758784d1Smistachkin if {$newGroup} {incr nGroup} 121758784d1Smistachkin } else { 122758784d1Smistachkin if {$prevName!="" && $group($prevName)} { 123758784d1Smistachkin incr nGroup 124758784d1Smistachkin } 125758784d1Smistachkin } 126b15393b8Sdrh set order($nOp) $name 127758784d1Smistachkin set prevName $name 128b15393b8Sdrh incr nOp 129b15393b8Sdrh } 130b15393b8Sdrh} 131b15393b8Sdrh 132b15393b8Sdrh# Assign numbers to all opcodes and output the result. 133b15393b8Sdrh# 134b15393b8Sdrhputs "/* Automatically generated. Do not edit */" 135b15393b8Sdrhputs "/* See the tool/mkopcodeh.tcl script for details */" 1364031bafaSdrhforeach name {OP_Noop OP_Explain OP_Abortable} { 137ed94af5eSdrh set jump($name) 0 138ed94af5eSdrh set in1($name) 0 139ed94af5eSdrh set in2($name) 0 140ed94af5eSdrh set in3($name) 0 141ed94af5eSdrh set out2($name) 0 142ed94af5eSdrh set out3($name) 0 143ed94af5eSdrh set op($name) -1 144ed94af5eSdrh set order($nOp) $name 145b15393b8Sdrh incr nOp 146ed94af5eSdrh} 147b15393b8Sdrh 148e74ca517Sdrh# The following are the opcodes that receive special processing in the 149e74ca517Sdrh# resolveP2Values() routine. Update this list whenever new cases are 150e74ca517Sdrh# added to the pOp->opcode switch within resolveP2Values(). 151b15393b8Sdrh# 152b15393b8Sdrhset rp2v_ops { 153b15393b8Sdrh OP_Transaction 154b15393b8Sdrh OP_AutoCommit 155b15393b8Sdrh OP_Savepoint 156b15393b8Sdrh OP_Checkpoint 157b15393b8Sdrh OP_Vacuum 158b15393b8Sdrh OP_JournalMode 159b15393b8Sdrh OP_VUpdate 160b15393b8Sdrh OP_VFilter 161*064390b2Sdrh OP_Init 162b15393b8Sdrh} 163b15393b8Sdrh 164e74ca517Sdrh# Assign the smallest values to opcodes that are processed by resolveP2Values() 165b15393b8Sdrh# to make code generation for the switch() statement smaller and faster. 166b15393b8Sdrh# 167ed94af5eSdrhset cnt -1 168b15393b8Sdrhfor {set i 0} {$i<$nOp} {incr i} { 169b15393b8Sdrh set name $order($i) 170b15393b8Sdrh if {[lsearch $rp2v_ops $name]>=0} { 171b15393b8Sdrh incr cnt 172b15393b8Sdrh while {[info exists used($cnt)]} {incr cnt} 173b15393b8Sdrh set op($name) $cnt 174b15393b8Sdrh set used($cnt) 1 175b15393b8Sdrh set def($cnt) $name 176b15393b8Sdrh } 177b15393b8Sdrh} 178e74ca517Sdrhset mxCase1 $cnt 179b15393b8Sdrh 1807cc84c2cSdrh# Assign the next group of values to JUMP opcodes 1817cc84c2cSdrh# 1827cc84c2cSdrhfor {set i 0} {$i<$nOp} {incr i} { 1837cc84c2cSdrh set name $order($i) 1847cc84c2cSdrh if {$op($name)>=0} continue 1857cc84c2cSdrh if {!$jump($name)} continue 1867cc84c2cSdrh incr cnt 1877cc84c2cSdrh while {[info exists used($cnt)]} {incr cnt} 1887cc84c2cSdrh set op($name) $cnt 1897cc84c2cSdrh set used($cnt) 1 1907cc84c2cSdrh set def($cnt) $name 1917cc84c2cSdrh} 1927cc84c2cSdrh 1937cc84c2cSdrh# Find the numeric value for the largest JUMP opcode 1947cc84c2cSdrh# 1957cc84c2cSdrhset mxJump -1 1967cc84c2cSdrhfor {set i 0} {$i<$nOp} {incr i} { 1977cc84c2cSdrh set name $order($i) 1987cc84c2cSdrh if {$jump($name) && $op($name)>$mxJump} {set mxJump $op($name)} 1997cc84c2cSdrh} 2007cc84c2cSdrh 2017cc84c2cSdrh 202758784d1Smistachkin# Generate the numeric values for all remaining opcodes, while 203758784d1Smistachkin# preserving any groupings of opcodes (i.e. those that must be 204758784d1Smistachkin# together). 205b15393b8Sdrh# 206758784d1Smistachkinfor {set g 0} {$g<$nGroup} {incr g} { 207758784d1Smistachkin set gLen [llength $groups($g)] 208758784d1Smistachkin set ok 0; set start -1 209f9ac1ab1Smistachkin set seek $cnt 210758784d1Smistachkin while {!$ok} { 211f9ac1ab1Smistachkin incr seek 212758784d1Smistachkin while {[info exists used($seek)]} {incr seek} 213758784d1Smistachkin set ok 1; set start $seek 214758784d1Smistachkin for {set j 0} {$j<$gLen} {incr j} { 215758784d1Smistachkin incr seek 216758784d1Smistachkin if {[info exists used($seek)]} { 217758784d1Smistachkin set ok 0; break 218758784d1Smistachkin } 219758784d1Smistachkin } 220758784d1Smistachkin } 221758784d1Smistachkin if {$ok} { 222758784d1Smistachkin set next $start 223758784d1Smistachkin for {set j 0} {$j<$gLen} {incr j} { 224758784d1Smistachkin set name [lindex $groups($g) $j] 225758784d1Smistachkin if {$op($name)>=0} continue 226758784d1Smistachkin set op($name) $next 227758784d1Smistachkin set used($next) 1 228758784d1Smistachkin set def($next) $name 229758784d1Smistachkin incr next 230758784d1Smistachkin } 231758784d1Smistachkin } else { 232758784d1Smistachkin error "cannot find opcodes for group: $groups($g)" 233758784d1Smistachkin } 234758784d1Smistachkin} 235758784d1Smistachkin 236b15393b8Sdrhfor {set i 0} {$i<$nOp} {incr i} { 237b15393b8Sdrh set name $order($i) 238b15393b8Sdrh if {$op($name)<0} { 239b15393b8Sdrh incr cnt 240b15393b8Sdrh while {[info exists used($cnt)]} {incr cnt} 241b15393b8Sdrh set op($name) $cnt 242b15393b8Sdrh set used($cnt) 1 243b15393b8Sdrh set def($cnt) $name 244b15393b8Sdrh } 245b15393b8Sdrh} 2460e6b8308Sdan 2470e6b8308Sdanset max [lindex [lsort -decr -integer [array names used]] 0] 2480e6b8308Sdanfor {set i 0} {$i<=$max} {incr i} { 249b15393b8Sdrh if {![info exists used($i)]} { 250b15393b8Sdrh set def($i) "OP_NotUsed_$i" 251b15393b8Sdrh } 2520e6b8308Sdan if {$i>$max} {set max $i} 253b15393b8Sdrh set name $def($i) 254b15393b8Sdrh puts -nonewline [format {#define %-16s %3d} $name $i] 255b15393b8Sdrh set com {} 256758784d1Smistachkin if {[info exists jump($name)] && $jump($name)} { 257a0286051Sdrh lappend com "jump" 258a0286051Sdrh } 259b15393b8Sdrh if {[info exists sameas($i)]} { 260a0286051Sdrh lappend com "same as $sameas($i)" 261b15393b8Sdrh } 262b15393b8Sdrh if {[info exists synopsis($name)]} { 263a0286051Sdrh lappend com "synopsis: $synopsis($name)" 264b15393b8Sdrh } 265a0286051Sdrh if {[llength $com]} { 266a0286051Sdrh puts -nonewline [format " /* %-42s */" [join $com {, }]] 267b15393b8Sdrh } 268b15393b8Sdrh puts "" 269b15393b8Sdrh} 270b15393b8Sdrh 2710e6b8308Sdanif {$max>255} { 2720e6b8308Sdan error "More than 255 opcodes - VdbeOp.opcode is of type u8!" 2730e6b8308Sdan} 2740e6b8308Sdan 275b15393b8Sdrh# Generate the bitvectors: 276b15393b8Sdrh# 277b15393b8Sdrhset bv(0) 0 278ed94af5eSdrhfor {set i 0} {$i<=$max} {incr i} { 279ed94af5eSdrh set x 0 2800e6b8308Sdan set name $def($i) 2810e6b8308Sdan if {[string match OP_NotUsed* $name]==0} { 282ed94af5eSdrh if {$jump($name)} {incr x 1} 283ed94af5eSdrh if {$in1($name)} {incr x 2} 284ed94af5eSdrh if {$in2($name)} {incr x 4} 285ed94af5eSdrh if {$in3($name)} {incr x 8} 286ed94af5eSdrh if {$out2($name)} {incr x 16} 287ed94af5eSdrh if {$out3($name)} {incr x 32} 2880e6b8308Sdan } 289ed94af5eSdrh set bv($i) $x 290b15393b8Sdrh} 291b15393b8Sdrhputs "" 292b15393b8Sdrhputs "/* Properties such as \"out2\" or \"jump\" that are specified in" 293b15393b8Sdrhputs "** comments following the \"case\" for each opcode in the vdbe.c" 294b15393b8Sdrhputs "** are encoded into bitvectors as follows:" 295b15393b8Sdrhputs "*/" 296ed94af5eSdrhputs "#define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */" 297ed94af5eSdrhputs "#define OPFLG_IN1 0x02 /* in1: P1 is an input */" 298ed94af5eSdrhputs "#define OPFLG_IN2 0x04 /* in2: P2 is an input */" 299ed94af5eSdrhputs "#define OPFLG_IN3 0x08 /* in3: P3 is an input */" 300ed94af5eSdrhputs "#define OPFLG_OUT2 0x10 /* out2: P2 is an output */" 301ed94af5eSdrhputs "#define OPFLG_OUT3 0x20 /* out3: P3 is an output */" 302b15393b8Sdrhputs "#define OPFLG_INITIALIZER \173\\" 303b15393b8Sdrhfor {set i 0} {$i<=$max} {incr i} { 304b15393b8Sdrh if {$i%8==0} { 305b15393b8Sdrh puts -nonewline [format "/* %3d */" $i] 306b15393b8Sdrh } 307b15393b8Sdrh puts -nonewline [format " 0x%02x," $bv($i)] 308b15393b8Sdrh if {$i%8==7} { 309b15393b8Sdrh puts "\\" 310b15393b8Sdrh } 311b15393b8Sdrh} 312b15393b8Sdrhputs "\175" 3137cc84c2cSdrhputs "" 314e74ca517Sdrhputs "/* The resolve3P2Values() routine is able to run faster if it knows" 3157cc84c2cSdrhputs "** the value of the largest JUMP opcode. The smaller the maximum" 3167cc84c2cSdrhputs "** JUMP opcode the better, so the mkopcodeh.tcl script that" 3177cc84c2cSdrhputs "** generated this include file strives to group all JUMP opcodes" 3187cc84c2cSdrhputs "** together near the beginning of the list." 3197cc84c2cSdrhputs "*/" 320c310db39Sdrhputs "#define SQLITE_MX_JUMP_OPCODE $mxJump /* Maximum JUMP opcode */" 321