Ark Compiler
一个简单的编译器,本科时几个人合作写的,起的名字比较好玩。
实现了 parser、lexer、AST、符号表,以及在此之上的简单类型检查、结构体、重载、指针等高阶特性,虽然比较简单但功能相对完整。不过其实应该算一个编译器前端,能够将 Pascal 语言编译成一种三地址中间码。
例:一个 gcd 算法(最大公约数),输入两个整数,输出它们的最大公约数。涉及到指针、函数、递归、重载等必要特性。
1 2 3 4 5 6 7 8 9 10 11 program example(input,output);var x,y:integer;function gcd (a,b:integer) : integer; begin if b=0 then gcd:=a else gcd:=gcd(b, a mod b) end ;begin read (x, y); write (gcd(x, y))end .
编译结果:本来是想接入 LLVM 作为后端,但是因为时间关系没有做到,暂且输出一种 C 的三地址中间码。更复杂例子请查看附录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 #include "stdio.h" #include "stdlib.h" #include "string.h" typedef char * string;int ____nouse = 1 ;void assign_string_ (string* a, string b) { if (*a) free (*a); char * p = malloc (strlen (b) + 1 ); strcpy (p, b); *a = p; }string add_string_ (string a, string b) { char * c = malloc (strlen (a) + strlen (b) + 1 ); strcpy (c, a); strcpy (c + strlen (a), b); return c; }string new_string_ (const char * s) { string p = malloc (strlen (s) + 1 ); strcpy (p, s); return p; }void read_integer_integer (int * a2,int * a1) { scanf ("%d%d" , a2, a1); }void write_integer (int a1) { printf ("%d" , a1); }int t0_0=0 ;int t0_1=0 ;void init_global_var_ () { }int x;int y;int gcd_integer_integer (int a, int b) {int __ret;int t2_0; (t2_0)=(b)==(t0_0);if (t2_0)goto L0; {int t3_0; (t3_0)=(a)%(b);int t3_1; (t3_1)=gcd_integer_integer ((b),(t3_0)); (__ret)=(t3_1); }goto L1; L0: ____nouse=1 ;; { (__ret)=(a); } L1: ____nouse=1 ;;return __ret; }int main () {init_global_var_ ();int __ret;read_integer_integer (&(x),&(y));int t2_0; (t2_0)=gcd_integer_integer ((x),(y));write_integer ((t2_0));return t0_1;return __ret; }
设计
Lexer
词法分析器使用了 Flex 生成的有限自动机,将源代码转为 token 流,并检查词法错误。
Parser
虽然有考虑过用 LR(1) 文法的分析器,但是在参考 Rust 实现及 LLVM 官方教程后,考虑到 LR(1) 功能还是过于僵硬、不易调试、错误恢复困难等问题,最终权衡利弊下还是使用了手写的递归下降分析器。
Parser 会将 token 流转为我们内部的 AST,并检查语法错误。
AST
我负责实现了 AST、符号表与后续的中间代码生成。
AST 中包含了一些节点,有
AST:基类
BlockAST:代码块。由于 Pascal 的代码块不返回值,所以单独对待。
ExprAST:带有返回值的表达式。
TypeDeclAST:类型声明表达式的基类。
BasicTypeAST:基本类型,如 int。
TypeDefAST:自定义类型。
PointerTypeDeclAST:定义指针类型。
ArrayTypeDeclAST:定义数组类型。
NumberExprAST:数字常量。
StringExprAST:字符串常量。
CharExprAST:字符常量。
VariableExprAST:变量引用。
UnaryExprAST:一元运算符。
BinaryExprAST:二元运算符。
ReturnAST:返回语句。
CallExprAST:函数调用。
VariableDeclAST:变量声明。
ForStatementAST:for 语句。
WhileStatementAST:while 语句。
IfStatementAST:if 语句。
FunctionSignatureAST:函数签名,不包含函数体。
FunctionAST:函数定义。
StructDeclAST:结构体定义。
GlobalAST:全局 AST。
符号表与描述符
编译器实现了符号表,实现了作用域等必要功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class _SymbolTable { int next_slot; std::map<std::string, SymbolDescriptor*> refType; std::map<std::string, VariableDescriptor*> refVar; std::map<std::pair<SymbolDescriptor*, int >, std::string> hasArrayType; std::map<SymbolDescriptor*, std::string> hasPointerType; };class SymbolTable { private : static _SymbolTable* root; static _SymbolTable* current; };class TagTable { static int next_slot; };
描述符包括
SymbolDescriptor:基类
TypeDescriptor:类型描述符
PointerTypeDescriptor:指针类型描述符
ArrayTypeDescriptor:数组类型描述符
VariableDescriptor:变量描述符
StructDescriptor:结构体描述符
FunctionDescriptor:函数描述符
中间代码生成
代码生成主要由 Dispatcher
在 AST 上遍历完成。AST 定义了 dispatcher 的遍历顺序,并由 dispatcher 负责生成代码。这种设计使得未来可以相对方便地替换 dispatcher 从而对接其他后端,比如 LLVM(虽然最后还是没时间换了)。生成过程中将检查语义错误。
dispatcher 将代码插入至 Collector
,并按照中间代码的结构顺序作最后编排,编译为中间代码。后续由 gcc 编译为目标程序。
以及一点可视化
这个纯属课程作业的附带需求。由小组另一位兄弟 完成:https://gr.yiren.lu/
开源
代码于 github 公开:https://github.com/Harmaney/ark_compiler
团体名字和项目名字只是因为有趣,没有特别的意思。
不过代码质量写得没那么好,建议只编译后玩玩 files 文件下附带的 examples。
附录:更多例子
以下附带二维数组、0-1 背包、快速排序三个复杂样例。其他更多样例可查看开源地址。
二维数组
源代码
1 2 3 4 5 6 7 8 program Hello;var a:array [1 ..10 ,10 ..20 ] of integer;begin a[1 ,14 ]:=2 ; a[2 ,12 ]:=3 ; a[10 ,20 ]:=a[1 ,14 ]+a[2 ,12 ]; write (a[10 ,20 ]);end .
中间代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 #include "stdio.h" #include "stdlib.h" #include "string.h" typedef char * string ;int ____nouse = 1 ;void assign_string_ (string * a, string b) { if (*a) free (*a); char * p = malloc (strlen (b) + 1 ); strcpy (p, b); *a = p; }string add_string_ (string a, string b) { char * c = malloc (strlen (a) + strlen (b) + 1 ); strcpy (c, a); strcpy (c + strlen (a), b); return c; }string new_string_ (const char * s) { string p = malloc (strlen (s) + 1 ); strcpy (p, s); return p; }void write_integer (int a1) { printf ("%d" , a1); }int t0_2=1 ;int t0_3=14 ;int t0_4=2 ;int t0_5=2 ;int t0_6=12 ;int t0_7=3 ;int t0_8=10 ;int t0_9=20 ;int t0_10=1 ;int t0_11=14 ;int t0_12=2 ;int t0_13=12 ;int t0_14=10 ;int t0_15=20 ;int t0_16=0 ;typedef int t0_0[11 ];typedef t0_0 t0_1[10 ];void init_global_var_ () { } t0_1 a;int main () { init_global_var_();int __ret;int t2_0=(t2_0)-1 ; t0_0* t2_1; t2_1=&(a)[(t0_2)];int t2_2=(t2_2)-10 ;int * t2_3; t2_3=&(*t2_1)[(t0_3)]; (*t2_3)=(t0_4);int t2_4=(t2_4)-1 ; t0_0* t2_5; t2_5=&(a)[(t0_5)];int t2_6=(t2_6)-10 ;int * t2_7; t2_7=&(*t2_5)[(t0_6)]; (*t2_7)=(t0_7);int t2_8=(t2_8)-1 ; t0_0* t2_9; t2_9=&(a)[(t0_8)];int t2_10=(t2_10)-10 ;int * t2_11; t2_11=&(*t2_9)[(t0_9)];int t2_12=(t2_12)-1 ; t0_0* t2_13; t2_13=&(a)[(t0_10)];int t2_14=(t2_14)-10 ;int * t2_15; t2_15=&(*t2_13)[(t0_11)];int t2_16=(t2_16)-1 ; t0_0* t2_17; t2_17=&(a)[(t0_12)];int t2_18=(t2_18)-10 ;int * t2_19; t2_19=&(*t2_17)[(t0_13)];int t2_20; (t2_20)=(*t2_15)+(*t2_19); (*t2_11)=(t2_20);int t2_21=(t2_21)-1 ; t0_0* t2_22; t2_22=&(a)[(t0_14)];int t2_23=(t2_23)-10 ;int * t2_24; t2_24=&(*t2_22)[(t0_15)]; write_integer((*t2_24));return t0_16;return __ret; }
0-1 背包
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 program backpack;var c,n:longint;f,w,v:array [0 ..1005 ] of longint;var i,j:longint;function max (i,j:longint) : longint;begin if i<j then max:=j else max:=i;end ;begin read (c,n); for i:=1 to n do read (w[i],v[i]); for i:=1 to n do begin j:=C; while j>=w[i] do begin f[j]:=max(f[j],f[j-w[i]]+v[i]); j:=j-1 ; end ; end ; write (f[c]);end .
中间代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 #include "stdio.h" #include "stdlib.h" #include "string.h" typedef char * string ;int ____nouse = 1 ;void assign_string_ (string * a, string b) { if (*a) free (*a); char * p = malloc (strlen (b) + 1 ); strcpy (p, b); *a = p; }string add_string_ (string a, string b) { char * c = malloc (strlen (a) + strlen (b) + 1 ); strcpy (c, a); strcpy (c + strlen (a), b); return c; }string new_string_ (const char * s) { string p = malloc (strlen (s) + 1 ); strcpy (p, s); return p; }void read_longint_longint (int * a2,int * a1) { scanf ("%d%d" , a2, a1); }void write_longint (int a1) { printf ("%d" , a1); }int t0_3=1 ;int t0_4=1 ;int t0_5=1 ;int t0_6=0 ;typedef int t0_0[1006 ];typedef int t0_1[1006 ];typedef int t0_2[1006 ];void init_global_var_ () { }int i;int j;int c;int n; t0_0 f; t0_1 w; t0_2 v;int max_longint_longint (int i, int j) {int __ret;int t2_0; (t2_0)=(i)<(j);if (t2_0)goto L0; { (__ret)=(i); }goto L1; L0: ____nouse=1 ;; { (__ret)=(j); } L1: ____nouse=1 ;;return __ret; }int main () { init_global_var_();int __ret; read_longint_longint(&(c),&(n)); i = t0_3;if (i>n)goto L2; L3: ____nouse=1 ;; {int t3_0=(t3_0)-0 ;int * t3_1; t3_1=&(w)[(i)];int t3_2=(t3_2)-0 ;int * t3_3; t3_3=&(v)[(i)]; read_longint_longint(&(*t3_1),&(*t3_3)); } i++;if (i<=n)goto L3; L2: ____nouse=1 ;; i = t0_4;if (i>n)goto L4; L5: ____nouse=1 ;; { (j)=(__ret);int t3_0=(t3_0)-0 ;int * t3_1; t3_1=&(w)[(i)];int t3_2; (t3_2)=(j)>=(*t3_1);if (!t3_2)goto L6; L7: ____nouse=1 ;; {int t4_0=(t4_0)-0 ;int * t4_1; t4_1=&(f)[(j)];int t4_2=(t4_2)-0 ;int * t4_3; t4_3=&(f)[(j)];int t4_4=(t4_4)-0 ;int * t4_5; t4_5=&(w)[(i)];int t4_6; (t4_6)=(j)-(*t4_5);int t4_7=(t4_7)-0 ;int * t4_8; t4_8=&(f)[(t4_6)];int t4_9=(t4_9)-0 ;int * t4_10; t4_10=&(v)[(i)];int t4_11; (t4_11)=(*t4_8)+(*t4_10);int t4_12; (t4_12)=max_longint_longint((*t4_3),(t4_11)); (*t4_1)=(t4_12);int t4_13; (t4_13)=(j)-(t0_5); (j)=(t4_13); }int t3_3=(t3_3)-0 ;int * t3_4; t3_4=&(w)[(i)];int t3_5; (t3_5)=(j)>=(*t3_4);if (t3_5)goto L7; L6: ____nouse=1 ;; } i++;if (i<=n)goto L5; L4: ____nouse=1 ;;int t2_0=(t2_0)-0 ;int * t2_1; t2_1=&(f)[(c)]; write_longint((*t2_1));return t0_6;return __ret; }
快速排序
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 program quicksort(input,output);var a:array [0 ..200000 ] of int64;var n:int64;i:longint;procedure swap (var i,j:int64) ;var t:int64;begin t:=i; i:=j; j:=t;end ;procedure qsort (l,r:int64) ;var i,j,key:int64;var m:int64;begin if l>=r then exit (); i:=l; j:=r; m:=(l+r) div 2 ; key:=a[m]; swap(a[m],a[l]); while i<>j do begin while (a[j]>=key) and (i<j) do j:=j-1 ; while (a[i]<=key) and (i<j) do i:=i+1 ; swap(a[i],a[j]); end ; swap(a[l],a[i]); while (l < i) and (a[i] = a[i-1 ]) do i := i - 1 ; while (j < r) and (a[j] = a[j+1 ]) do j := j + 1 ; qsort(l,i-1 ); qsort(j+1 ,r);end ;begin read (n); for i:=1 to n do read (a[i]); qsort(1 ,n); for i:=1 to n do begin write (a[i]); if (i <> n) then write (' ' ); end ; write ('\n' );end .
中间代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 #include "stdio.h" #include "stdlib.h" #include "string.h" typedef char * string ;int ____nouse = 1 ;void assign_string_ (string * a, string b) { if (*a) free (*a); char * p = malloc (strlen (b) + 1 ); strcpy (p, b); *a = p; }string add_string_ (string a, string b) { char * c = malloc (strlen (a) + strlen (b) + 1 ); strcpy (c, a); strcpy (c + strlen (a), b); return c; }string new_string_ (const char * s) { string p = malloc (strlen (s) + 1 ); strcpy (p, s); return p; }void read_int64 (long long * a1) { scanf ("%lld" , a1); }void write_int64 (long long a1) { printf ("%lld" , a1); }void write_string (string a1) { printf ("%s" , a1); }int t0_1=2 ;int t0_2=1 ;int t0_3=1 ;int t0_4=1 ;int t0_5=1 ;int t0_6=1 ;int t0_7=1 ;int t0_8=1 ;int t0_9=1 ;int t0_10=1 ;int t0_11=1 ;int t0_12=1 ;int t0_13=1 ;int t0_14=1 ;string t0_15 = NULL ;string t0_16 = NULL ;int t0_17=0 ;typedef long long t0_0[200001 ];void init_global_var_ () { t0_15= new_string_(" " ); t0_16= new_string_("\n" ); }long long n;int i; t0_0 a;void swap_int64_int64 (long long * i, long long * j) {long long t; (t)=(*i); (*i)=(*j); (*j)=(t);int __ret; }void qsort_int64_int64 (long long l, long long r) {long long key;long long j;long long i;long long m;long long t2_0; (t2_0)=(l)>=(r);if (t2_0)goto L0; { }goto L1; L0: ____nouse=1 ;; {return ; } L1: ____nouse=1 ;; (i)=(l); (j)=(r);long long t2_1; (t2_1)=(l)+(r);long long t2_2; (t2_2)=(t2_1)/(t0_1); (m)=(t2_2);long long t2_3=(t2_3)-0 ;long long * t2_4; t2_4=&(a)[(m)]; (key)=(*t2_4);long long t2_5=(t2_5)-0 ;long long * t2_6; t2_6=&(a)[(m)];long long t2_7=(t2_7)-0 ;long long * t2_8; t2_8=&(a)[(l)]; swap_int64_int64(&(*t2_6),&(*t2_8));long long t2_9; (t2_9)=(i)!=(j);if (!t2_9)goto L2; L3: ____nouse=1 ;; {long long t3_0=(t3_0)-0 ;long long * t3_1; t3_1=&(a)[(j)];long long t3_2; (t3_2)=(*t3_1)>=(key);long long t3_3; (t3_3)=(i)<(j);long long t3_4; (t3_4)=(t3_2)&&(t3_3);if (!t3_4)goto L4; L5: ____nouse=1 ;; {long long t4_0; (t4_0)=(j)-(t0_2); (j)=(t4_0); }long long t3_5=(t3_5)-0 ;long long * t3_6; t3_6=&(a)[(j)];long long t3_7; (t3_7)=(*t3_6)>=(key);long long t3_8; (t3_8)=(i)<(j);long long t3_9; (t3_9)=(t3_7)&&(t3_8);if (t3_9)goto L5; L4: ____nouse=1 ;;long long t3_10=(t3_10)-0 ;long long * t3_11; t3_11=&(a)[(i)];long long t3_12; (t3_12)=(*t3_11)<=(key);long long t3_13; (t3_13)=(i)<(j);long long t3_14; (t3_14)=(t3_12)&&(t3_13);if (!t3_14)goto L6; L7: ____nouse=1 ;; {long long t4_0; (t4_0)=(i)+(t0_3); (i)=(t4_0); }long long t3_15=(t3_15)-0 ;long long * t3_16; t3_16=&(a)[(i)];long long t3_17; (t3_17)=(*t3_16)<=(key);long long t3_18; (t3_18)=(i)<(j);long long t3_19; (t3_19)=(t3_17)&&(t3_18);if (t3_19)goto L7; L6: ____nouse=1 ;;long long t3_20=(t3_20)-0 ;long long * t3_21; t3_21=&(a)[(i)];long long t3_22=(t3_22)-0 ;long long * t3_23; t3_23=&(a)[(j)]; swap_int64_int64(&(*t3_21),&(*t3_23)); }long long t2_10; (t2_10)=(i)!=(j);if (t2_10)goto L3; L2: ____nouse=1 ;;long long t2_11=(t2_11)-0 ;long long * t2_12; t2_12=&(a)[(l)];long long t2_13=(t2_13)-0 ;long long * t2_14; t2_14=&(a)[(i)]; swap_int64_int64(&(*t2_12),&(*t2_14));long long t2_15; (t2_15)=(l)<(i);long long t2_16=(t2_16)-0 ;long long * t2_17; t2_17=&(a)[(i)];long long t2_18; (t2_18)=(i)-(t0_4);long long t2_19=(t2_19)-0 ;long long * t2_20; t2_20=&(a)[(t2_18)];long long t2_21; (t2_21)=(*t2_17)==(*t2_20);long long t2_22; (t2_22)=(t2_15)&&(t2_21);if (!t2_22)goto L8; L9: ____nouse=1 ;; {long long t3_0; (t3_0)=(i)-(t0_5); (i)=(t3_0); }long long t2_23; (t2_23)=(l)<(i);long long t2_24=(t2_24)-0 ;long long * t2_25; t2_25=&(a)[(i)];long long t2_26; (t2_26)=(i)-(t0_6);long long t2_27=(t2_27)-0 ;long long * t2_28; t2_28=&(a)[(t2_26)];long long t2_29; (t2_29)=(*t2_25)==(*t2_28);long long t2_30; (t2_30)=(t2_23)&&(t2_29);if (t2_30)goto L9; L8: ____nouse=1 ;;long long t2_31; (t2_31)=(j)<(r);long long t2_32=(t2_32)-0 ;long long * t2_33; t2_33=&(a)[(j)];long long t2_34; (t2_34)=(j)+(t0_7);long long t2_35=(t2_35)-0 ;long long * t2_36; t2_36=&(a)[(t2_34)];long long t2_37; (t2_37)=(*t2_33)==(*t2_36);long long t2_38; (t2_38)=(t2_31)&&(t2_37);if (!t2_38)goto L10; L11: ____nouse=1 ;; {long long t3_0; (t3_0)=(j)+(t0_8); (j)=(t3_0); }long long t2_39; (t2_39)=(j)<(r);long long t2_40=(t2_40)-0 ;long long * t2_41; t2_41=&(a)[(j)];long long t2_42; (t2_42)=(j)+(t0_9);long long t2_43=(t2_43)-0 ;long long * t2_44; t2_44=&(a)[(t2_42)];long long t2_45; (t2_45)=(*t2_41)==(*t2_44);long long t2_46; (t2_46)=(t2_39)&&(t2_45);if (t2_46)goto L11; L10: ____nouse=1 ;;long long t2_47; (t2_47)=(i)-(t0_10); qsort_int64_int64((l),(t2_47));long long t2_48; (t2_48)=(j)+(t0_11); qsort_int64_int64((t2_48),(r));int __ret; }int main () { init_global_var_();int __ret; read_int64(&(n)); i = t0_12;if (i>n)goto L12; L13: ____nouse=1 ;; {int t3_0=(t3_0)-0 ;long long * t3_1; t3_1=&(a)[(i)]; read_int64(&(*t3_1)); } i++;if (i<=n)goto L13; L12: ____nouse=1 ;; qsort_int64_int64((t0_13),(n)); i = t0_14;if (i>n)goto L14; L15: ____nouse=1 ;; {int t3_0=(t3_0)-0 ;long long * t3_1; t3_1=&(a)[(i)]; write_int64((*t3_1));int t3_2; (t3_2)=(i)!=(n);if (t3_2)goto L16; { }goto L17; L16: ____nouse=1 ;; { write_string((t0_15)); } L17: ____nouse=1 ;; } i++;if (i<=n)goto L15; L14: ____nouse=1 ;; write_string((t0_16));return t0_17;return __ret; }