1#!/usr/bin/awk -f
2#
3# Generate the file opcodes.h.
4#
5# This AWK script scans a concatenation of the parse.h output file from the
6# parser and the vdbe.c source file in order to generate the opcodes numbers
7# for all opcodes.  
8#
9# The lines of the vdbe.c that we are interested in are of the form:
10#
11#       case OP_aaaa:      /* same as TK_bbbbb */
12#
13# The TK_ comment is optional.  If it is present, then the value assigned to
14# the OP_ is the same as the TK_ value.  If missing, the OP_ value is assigned
15# a small integer that is different from every other OP_ value.
16#
17# We go to the trouble of making some OP_ values the same as TK_ values
18# as an optimization.  During parsing, things like expression operators
19# are coded with TK_ values such as TK_ADD, TK_DIVIDE, and so forth.  Later
20# during code generation, we need to generate corresponding opcodes like
21# OP_Add and OP_Divide.  By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide,
22# code to translate from one to the other is avoided.  This makes the
23# code generator run (infinitesimally) faster and more importantly it makes
24# the library footprint smaller.
25#
26# This script also scans for lines of the form:
27#
28#       case OP_aaaa:       /* jump, in1, in2, in3, out2-prerelease, out3 */
29#
30# When such comments are found on an opcode, it means that certain
31# properties apply to that opcode.  Set corresponding flags using the
32# OPFLG_INITIALIZER macro.
33#
34
35
36# Remember the TK_ values from the parse.h file
37/^#define TK_/ {
38  tk[$2] = 0+$3
39}
40
41# Scan for "case OP_aaaa:" lines in the vdbe.c file
42/^case OP_/ {
43  name = $2
44  sub(/:/,"",name)
45  sub("\r","",name)
46  op[name] = -1
47  jump[name] = 0
48  out2_prerelease[name] = 0
49  in1[name] = 0
50  in2[name] = 0
51  in3[name] = 0
52  out2[name] = 0
53  out3[name] = 0
54  for(i=3; i<NF; i++){
55    if($i=="same" && $(i+1)=="as"){
56      sym = $(i+2)
57      sub(/,/,"",sym)
58      op[name] = tk[sym]
59      used[op[name]] = 1
60      sameas[op[name]] = sym
61    }
62    x = $i
63    sub(",","",x)
64    if(x=="jump"){
65      jump[name] = 1
66    }else if(x=="out2-prerelease"){
67      out2_prerelease[name] = 1
68    }else if(x=="in1"){
69      in1[name] = 1
70    }else if(x=="in2"){
71      in2[name] = 1
72    }else if(x=="in3"){
73      in3[name] = 1
74    }else if(x=="out2"){
75      out2[name] = 1
76    }else if(x=="out3"){
77      out3[name] = 1
78    }
79  }
80  order[n_op++] = name;
81}
82
83# Assign numbers to all opcodes and output the result.
84END {
85  cnt = 0
86  max = 0
87  print "/* Automatically generated.  Do not edit */"
88  print "/* See the mkopcodeh.awk script for details */"
89  op["OP_Noop"] = -1;
90  order[n_op++] = "OP_Noop";
91  op["OP_Explain"] = -1;
92  order[n_op++] = "OP_Explain";
93  for(i=0; i<n_op; i++){
94    name = order[i];
95    if( op[name]<0 ){
96      cnt++
97      while( used[cnt] ) cnt++
98      op[name] = cnt
99    }
100    used[op[name]] = 1;
101    if( op[name]>max ) max = op[name]
102    printf "#define %-25s %15d", name, op[name]
103    if( sameas[op[name]] ) {
104      printf "   /* same as %-12s*/", sameas[op[name]]
105    } 
106    printf "\n"
107
108  }
109  seenUnused = 0;
110  for(i=1; i<max; i++){
111    if( !used[i] ){
112      if( !seenUnused ){
113        printf "\n/* The following opcode values are never used */\n"
114        seenUnused = 1
115      }
116      printf "#define %-25s %15d\n", sprintf( "OP_NotUsed_%-3d", i ), i
117    }
118  }
119
120  # Generate the bitvectors:
121  #
122  #  bit 0:     jump
123  #  bit 1:     pushes a result onto stack
124  #  bit 2:     output to p1.  release p1 before opcode runs
125  #
126  for(i=0; i<=max; i++) bv[i] = 0;
127  for(i=0; i<n_op; i++){
128    name = order[i];
129    x = op[name]
130    a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = 0
131    # a7 = a9 = a10 = a11 = a12 = a13 = a14 = a15 = 0
132    if( jump[name] ) a0 = 1;
133    if( out2_prerelease[name] ) a1 = 2;
134    if( in1[name] ) a2 = 4;
135    if( in2[name] ) a3 = 8;
136    if( in3[name] ) a4 = 16;
137    if( out2[name] ) a5 = 32;
138    if( out3[name] ) a6 = 64;
139    # bv[x] = a0+a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12+a13+a14+a15;
140    bv[x] = a0+a1+a2+a3+a4+a5+a6+a7;
141  }
142  print "\n"
143  print "/* Properties such as \"out2\" or \"jump\" that are specified in"
144  print "** comments following the \"case\" for each opcode in the vdbe.c"
145  print "** are encoded into bitvectors as follows:"
146  print "*/"
147  print "#define OPFLG_JUMP            0x0001  /* jump:  P2 holds jmp target */"
148  print "#define OPFLG_OUT2_PRERELEASE 0x0002  /* out2-prerelease: */"
149  print "#define OPFLG_IN1             0x0004  /* in1:   P1 is an input */"
150  print "#define OPFLG_IN2             0x0008  /* in2:   P2 is an input */"
151  print "#define OPFLG_IN3             0x0010  /* in3:   P3 is an input */"
152  print "#define OPFLG_OUT2            0x0020  /* out2:  P2 is an output */"
153  print "#define OPFLG_OUT3            0x0040  /* out3:  P3 is an output */"
154  print "#define OPFLG_INITIALIZER {\\"
155  for(i=0; i<=max; i++){
156    if( i%8==0 ) printf("/* %3d */",i)
157    printf " 0x%02x,", bv[i]
158    if( i%8==7 ) printf("\\\n");
159  }
160  print "}"
161}
162