With sqlite3 3110100, which is used in MaxScale, the the generation
of the used op-codes could sometime generate code that did not define
all opcodes. That resulted then in a compilation error like:
.../sqlite-bld-3110100/sqlite3.c: In function 'sqlite3VdbeExec':
.../sqlite-bld-3110100/sqlite3.c:75427:6: error: 'OP_Real' undeclared
                                          (first use in this function)
 case OP_Real: {            /* same as TK_FLOAT, out2 */
      ^
The reason seems to be that if a particular op-code was not used, the
generation stopped at that point:
    #define OP_Explain       160
    #define OP_NotUsed_161   161
With mkopcodeh.tcl from sqlite3 version 3200000, the generated code
looks like
    #define OP_NotUsed_161   161
    #define OP_Real          162 /* same as TK_FLOAT,
                                    synopsis: r[P2]=P4       */
and the code compiles.
Thus, mkopcodeh.tsl is updated from the newer sqlite3 version.
		
	
		
			
				
	
	
		
			272 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Tcl
		
	
	
	
	
	
			
		
		
	
	
			272 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Tcl
		
	
	
	
	
	
#!/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 [lindex [lsort -decr -integer [array names used]] 0]
 | 
						|
for {set i 0} {$i<=$max} {incr i} {
 | 
						|
  if {![info exists used($i)]} {
 | 
						|
    set def($i) "OP_NotUsed_$i"
 | 
						|
  }
 | 
						|
  if {$i>$max} {set max $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 ""
 | 
						|
}
 | 
						|
 | 
						|
if {$max>255} {
 | 
						|
  error "More than 255 opcodes - VdbeOp.opcode is of type u8!"
 | 
						|
}
 | 
						|
 | 
						|
# Generate the bitvectors:
 | 
						|
#
 | 
						|
set bv(0) 0
 | 
						|
for {set i 0} {$i<=$max} {incr i} {
 | 
						|
  set x 0
 | 
						|
  set name $def($i)
 | 
						|
  if {[string match OP_NotUsed* $name]==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 */"
 |