home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #3 / NN_1993_3.iso / spool / alt / sources / 3073 < prev    next >
Encoding:
Text File  |  1993-01-23  |  49.5 KB  |  1,348 lines

  1. Newsgroups: alt.sources
  2. Path: sparky!uunet!cs.utexas.edu!qt.cs.utexas.edu!yale.edu!newsserver.jvnc.net!princeton!csservices!tyrolia!mg
  3. From: mg@tyrolia (Michael Golan)
  4. Subject: Duel - a language for debugging C programs part 5/6
  5. Message-ID: <1993Jan22.034806.21255@csservices.Princeton.EDU>
  6. Sender: news@csservices.Princeton.EDU (USENET News System)
  7. Organization: Department of Computer Science, Princeton University
  8. Date: Fri, 22 Jan 1993 03:48:06 GMT
  9. Lines: 1337
  10.  
  11. Submitted-by: mg@cs.princeton.edu
  12. Archive-name: duel/part05
  13.  
  14. #!/bin/sh
  15. # This is part 05 of duel
  16. if touch 2>&1 | fgrep 'amc' > /dev/null
  17.  then TOUCH=touch
  18.  else TOUCH=true
  19. fi
  20. # ============= src/evalops.c ==============
  21. echo "x - extracting src/evalops.c (Text)"
  22. sed 's/^X//' << 'SHAR_EOF' > src/evalops.c &&
  23. X/*   DUEL - A Very High Level Debugging Langauge.  */
  24. X/*   Public domain code                            */
  25. X/*   Written by Michael Golan mg@cs.princeton.edu  */
  26. X/*$Header: /tmp_mnt/n/fs/grad2/mg/duel/RCS/evalops.c,v 1.8 93/01/12 21:51:29 mg Exp $*/
  27. X
  28. X/* this module contains evalauation code for many standard operators, eg '+'
  29. X */
  30. X
  31. X/*
  32. X * $Log:    evalops.c,v $
  33. X * Revision 1.8  93/01/12  21:51:29  mg
  34. X * cleanup and set for release
  35. X * 
  36. X * Revision 1.7  93/01/07  00:10:51  mg
  37. X * auto convert func to &func
  38. X * find a frame for a func
  39. X * 
  40. X * 
  41. X * Revision 1.6  93/01/03  07:30:02  mg
  42. X * function calls, error reporting, printing.
  43. X * 
  44. X * Revision 1.5  92/12/24  23:34:47  mg
  45. X * frames support
  46. X * 
  47. X * Revision 1.4  92/10/19  15:07:46  mg
  48. X * fvalue added (not ready yet), svalues dropped
  49. X * 
  50. X * Revision 1.3  92/10/14  02:05:10  mg
  51. X * add print/{x} support
  52. X * 
  53. X * Revision 1.2  92/09/15  05:48:57  mg
  54. X * support '..' new formats
  55. X * 
  56. X */
  57. X
  58. X#include "duel.h"
  59. X
  60. X/*
  61. X * This file is made up of three parts:
  62. X * (1) low-level functions that interact with the debugger/type system directly
  63. X * (2) mid-level functions that compute the result of simple operators like '+'
  64. X * (3) high-level functions that compute any binary/unary op.
  65. X * Only some of the functions in (1) are global, and all of the (3) are.
  66. X * this collection is in one file to allow a minimal of global symbols
  67. X * (for minimum collision with the debugger)
  68. X */
  69. X
  70. X
  71. X
  72. X/****************************************************************************
  73. X A low-level set of functions follows. They interact with the type system
  74. X and the debugger/target's space directly:
  75. X get_storage_type_kind - retrieve ctype_kind, with special conversion for enums
  76. X get_rvalue - retrieve the rvalue of a variable/lvalue.
  77. X set_symb_val - set the symbolic value of a tvalue.
  78. X upgrade_small_int_types - figure out the type to upgrade to from char etc.
  79. X find_numeric_result_type - figure type of x+y where + is generic C op
  80. X convert_scalar_type - convert one scalar type to another
  81. X get_numeric_val - retrieve rvalue, making sure it is numeric
  82. X get_scalar_val  - retrieve rvalue, making sure it is numeric or pointer
  83. X get_integral_val- retrieve rvalue, making sure it is an integer
  84. X get_int_val     - retrieve rvalue, make sure it's an integer, return int val
  85. X get_pointer_val - retrieve rvalue, make sure it's a pointer.
  86. X ****************************************************************************/ 
  87. X
  88. X/* give the storage-type kind of a given type. 
  89. X * this is the same type-kind as the type itslef, except in the case of enums
  90. X * where the type-kind of the storage will be CTK_INT etc (integral type)
  91. X * the storage type kind is set when the enum is created.
  92. X */
  93. X
  94. XLFUNC tctype_kind get_storage_type_kind(tctype *t)
  95. X{
  96. X    if(t->type_kind!=CTK_ENUM) return t->type_kind ;
  97. X    return t->u.e.real_type_kind ;
  98. X}
  99. X
  100. X/* try_get_rvalue -- make an rvalue of v. if v is already an rvalue, 
  101. X * nothing is done. Else v is an b/lvalue, so its rvalue is fetched.
  102. X * special care:
  103. X * (1) Enums are fetched as int of same size. type stay enum!
  104. X * (2) Arrays and functions are made into pointers
  105. X * (3) Bitfields are converted to ints (debugger dependent)
  106. X *     there are no rvalues of 'bitfield' type!
  107. X * return succ/fail for bad mem ref. the "real" function everyone calls is
  108. X * get_rvalue (this function is used only by printing functions to avoid
  109. X * chicken&egg problem of error reporting.)
  110. X */
  111. X
  112. XFUNC duel_try_get_rvalue(tvalue *v,char *op)
  113. X{
  114. X   void *p ;
  115. X   int n ;
  116. X   bool ok;
  117. X   if(v->val_kind == VK_RVALUE) return TRUE;
  118. X   if(v->val_kind == VK_FVALUE) 
  119. X       duel_op_error("illegal type 'frame' for operand x of '%s'",op,v,0);
  120. X   switch(get_storage_type_kind(v->ctype)) {
  121. X      case CTK_CHAR:    p= &v->u.rval_char   ; n=sizeof(char)         ;break ;
  122. X      case CTK_UCHAR:   p= &v->u.rval_uchar  ; n=sizeof(uchar)        ;break ;
  123. X      case CTK_USHORT:  p= &v->u.rval_ushort ; n=sizeof(ushort)       ;break ;
  124. X      case CTK_SHORT:   p= &v->u.rval_short  ; n=sizeof(short)        ;break ;
  125. X      case CTK_INT:     p= &v->u.rval_int    ; n=sizeof(int)          ;break ;
  126. X      case CTK_UINT:    p= &v->u.rval_uint   ; n=sizeof(uint)         ;break ;
  127. X      case CTK_LONG:    p= &v->u.rval_long   ; n=sizeof(long)         ;break ;
  128. X      case CTK_ULONG:   p= &v->u.rval_ulong  ; n=sizeof(ulong)        ;break ;
  129. X      case CTK_FLOAT:   p= &v->u.rval_float  ; n=sizeof(float)        ;break ;
  130. X      case CTK_DOUBLE:  p= &v->u.rval_double ; n=sizeof(double)       ;break ;
  131. X      case CTK_PTR:     p= &v->u.rval_ptr    ; n=sizeof(ttarget_ptr) ;break ;
  132. X      case CTK_ARRAY:   /* the lvalue becomes an rvalue, a real pointer! */
  133. X                 duel_assert(v->val_kind==VK_LVALUE); /* duel exp rules */
  134. X                 v->val_kind=VK_RVALUE ;
  135. X                 v->ctype=duel_mkctype_ptr(v->ctype->u.kid) ;
  136. X                 v->u.rval_ptr=v->u.lvalue ;
  137. X                 return TRUE;   
  138. X      case CTK_FUNC:   /* makes it a pointer to a func*/
  139. X                 duel_assert(v->val_kind==VK_LVALUE); /* duel exp rules */
  140. X                 v->val_kind=VK_RVALUE ;
  141. X                 v->ctype=duel_mkctype_ptr(v->ctype) ;
  142. X                 v->u.rval_ptr=v->u.lvalue ;
  143. X                 return TRUE;   
  144. X
  145. X      case CTK_STRUCT: /* can't have an rval from struct? */
  146. X      case CTK_UNION:  
  147. X      /* enums were eliminated above */
  148. X      default: duel_assert(0);
  149. X   }
  150. X   if(v->val_kind == VK_BVALUE) {        /* bitfield: lvalue+bitpos/len */
  151. X       tbvalue_info bv; 
  152. X       bv=v->u.bvalue ;
  153. X       ok=duel_get_target_bitfield(bv.lvalue, bv.bitpos, bv.bitlen, p,
  154. X                                    v->ctype->type_kind);
  155. X       if(!ok) { v->u.bvalue=bv ; return FALSE ; } 
  156. X   }
  157. X   else {
  158. X       ttarget_ptr lv=v->u.lvalue ;
  159. X       ok=duel_get_target_bytes(lv,p,n); /*fetch n debuggee bytes*/
  160. X       if(!ok) { v->u.lvalue=lv ; return FALSE ; }
  161. X   }
  162. X
  163. X   v->val_kind=VK_RVALUE ;
  164. X   /* in remote debugging, one might need to swap byte order at this
  165. X    * point. [remote debugging is not supported by duel v1.0]
  166. X    */
  167. X   return TRUE ;
  168. X}
  169. X
  170. X
  171. X/*
  172. X * safe get_rvalue - produce error messages on memory access failer.
  173. X */
  174. X
  175. XLPROC get_rvalue(tvalue *v,char *op)
  176. X{
  177. X   bool ok=duel_try_get_rvalue(v,op);
  178. X   if(!ok) duel_op_error("illegal address for operand x of '%s'",op,v,0);
  179. X}
  180. X
  181. X/* put_rvalue: put the rvalue of v2 into the location in v1.
  182. X * types are assumed to be the same.
  183. X */
  184. X
  185. XLPROC put_rvalue(tvalue *v1,tvalue *v2,char *op)
  186. X{
  187. X   void *p ;
  188. X   int n ;
  189. X   duel_assert(v1->val_kind!=VK_RVALUE);
  190. X   duel_assert(v1->val_kind!=VK_FVALUE);
  191. X   duel_assert(v2->val_kind==VK_RVALUE);
  192. X   duel_assert(v1->ctype->size == v2->ctype->size);
  193. X   switch(get_storage_type_kind(v2->ctype)) {
  194. X      case CTK_CHAR:    p= &v2->u.rval_char   ; n=sizeof(char)         ;break ;
  195. X      case CTK_UCHAR:   p= &v2->u.rval_uchar  ; n=sizeof(uchar)        ;break ;
  196. X      case CTK_USHORT:  p= &v2->u.rval_ushort ; n=sizeof(ushort)       ;break ;
  197. X      case CTK_SHORT:   p= &v2->u.rval_short  ; n=sizeof(short)        ;break ;
  198. X      case CTK_INT:     p= &v2->u.rval_int    ; n=sizeof(int)          ;break ;
  199. X      case CTK_UINT:    p= &v2->u.rval_uint   ; n=sizeof(uint)         ;break ;
  200. X      case CTK_LONG:    p= &v2->u.rval_long   ; n=sizeof(long)         ;break ;
  201. X      case CTK_ULONG:   p= &v2->u.rval_ulong  ; n=sizeof(ulong)        ;break ;
  202. X      case CTK_FLOAT:   p= &v2->u.rval_float  ; n=sizeof(float)        ;break ;
  203. X      case CTK_DOUBLE:  p= &v2->u.rval_double ; n=sizeof(double)       ;break ;
  204. X      case CTK_PTR:     p= &v2->u.rval_ptr    ; n=sizeof(ttarget_ptr) ;break ;
  205. X      default: duel_assert(0);  /* other types not supported as rvalues */
  206. X   }
  207. X   if(v1->val_kind == VK_BVALUE) 
  208. X       duel_gen_error("assignment to bitfields is not yet supported",0);
  209. X   else
  210. X   if(!duel_put_target_bytes(v1->u.lvalue,p,n)) /*store n debuggee bytes*/
  211. X       duel_op_error("cant write memory for operand x of '%s'",op,v1,0);
  212. X}
  213. X
  214. X/* set the symbolic val for tvalue. input format is a sprintf,
  215. X * with v1,v2 being other values that show as '%s' in the format.
  216. X * v1,v2 can be zero if they are unused by the format.
  217. X */
  218. XPROC duel_set_symb_val(tvalue *r,char *format,tvalue *v1,tvalue *v2)
  219. X{
  220. X   char s[3*VALUE_MAX_SYMBOLIC_SIZE];
  221. X   sprintf(s,format,v1->symb_val,v2->symb_val);
  222. X   s[VALUE_MAX_SYMBOLIC_SIZE]=0 ; /* chop as needed */
  223. X   strcpy(r->symb_val,s);
  224. X}
  225. X
  226. X/* given a small int type (short,char,enum) return the upgraded (int or 
  227. X * uint) type. Else return the original type
  228. X */
  229. XLFUNC tctype* upgrade_small_int_types(tctype *t)
  230. X{
  231. X   switch(t->type_kind) {
  232. X      case CTK_ENUM:
  233. X      case CTK_CHAR:
  234. X      case CTK_UCHAR:
  235. X      case CTK_SHORT:
  236. X                     return ctype_int ;
  237. X      case CTK_USHORT:
  238. X                     if(sizeof(ushort)==sizeof(int)) return ctype_uint ;
  239. X                     else return ctype_int ;
  240. X        default:
  241. X                      return t ;    
  242. X   }
  243. X}
  244. X
  245. X/* find the type of the result of a generic numeric operation on
  246. X * v1,v2. This applies the standard C type upgrade rules.
  247. X * The type of the result is returned.
  248. X * r is setup so it can receive the result: an RVALUE of the specified
  249. X * type. Its symbolic value is also setup based on the symbolic value
  250. X * of v1 v2 and the operation op.
  251. X * Note: op is not used to figure out the numeric result, only
  252. X * the types of v1 and v2. As a side effect, the answer for x|y where
  253. X * y is a double will be given as double. it is up to the caller to
  254. X * verify that v1,v2 have meaningful types of this operation
  255. X * 
  256. X */
  257. X
  258. XLFUNC tctype* find_numeric_result_type(tvalue *v1,tvalue *v2,
  259. X                                          tvalue *r,char *op)
  260. X{
  261. X    tctype *t1=upgrade_small_int_types(v1->ctype);   /* upgrade to int etc */
  262. X    tctype *t2=upgrade_small_int_types(v2->ctype);
  263. X    char s[80] ;
  264. X    r->val_kind=VK_RVALUE ;
  265. X    sprintf(s,"%%s%s%%s",op) ;  /* eg, if op=">>" then s becomes "%s>>%s" */
  266. X    duel_set_symb_val(r,s,v1,v2);
  267. X
  268. X    if(t1==ctype_double || t2==ctype_double) return r->ctype=ctype_double ;
  269. X    if(t1==ctype_float  || t2==ctype_float)  return r->ctype=ctype_float ;
  270. X    if(t1==ctype_ulong  || t2==ctype_ulong)  return r->ctype=ctype_ulong ;
  271. X    if(sizeof(unsigned)==sizeof(long) &&
  272. X       (t1==ctype_long && t2==ctype_uint  ||
  273. X        t1==ctype_uint && t2==ctype_long))    return r->ctype=ctype_ulong ;
  274. X    if(t1==ctype_long  || t2==ctype_long)     return r->ctype=ctype_long ;
  275. X    if(t1==ctype_uint  || t2==ctype_uint)     return r->ctype=ctype_uint ;
  276. X    return r->ctype=ctype_int ;
  277. X}
  278. X
  279. X/* convert_to_fix assisting-macro: takes the val stored in v and put it
  280. X * into w. w is an lvalue with a 'fixed' type (t).
  281. X */
  282. X
  283. X#define convert_to_fix(v,w)                          \
  284. X     switch(get_storage_type_kind(v->ctype)) {         \
  285. X      case CTK_CHAR:    w v->u.rval_char     ; break ; \
  286. X      case CTK_UCHAR:   w v->u.rval_uchar    ; break ; \
  287. X      case CTK_USHORT:  w v->u.rval_ushort   ; break ; \
  288. X      case CTK_SHORT:   w v->u.rval_short    ; break ; \
  289. X      case CTK_INT:     w v->u.rval_int      ; break ; \
  290. X      case CTK_UINT:    w v->u.rval_uint     ; break ; \
  291. X      case CTK_LONG:    w v->u.rval_long     ; break ; \
  292. X      case CTK_ULONG:   w v->u.rval_ulong    ; break ; \
  293. X      case CTK_FLOAT:   w v->u.rval_float    ; break ; \
  294. X      case CTK_DOUBLE:  w v->u.rval_double   ; break ; \
  295. X      case CTK_PTR:     w (tptrsize_int) v->u.rval_ptr ; break ; \
  296. X      default: duel_assert(0);                         \
  297. X   }
  298. X
  299. X
  300. X/* convert_scalar_type -- convert rvalue v to type t.
  301. X * uses convert_to_fix macro. In effect, this is a huge switch for
  302. X * all possible combinations of basic C types.
  303. X */
  304. X
  305. XLPROC convert_scalar_type(tvalue *v,tctype *t,char *op)
  306. X{
  307. X   get_rvalue(v,op);
  308. X   switch(get_storage_type_kind(t)) {
  309. X      case CTK_CHAR:   convert_to_fix(v,v->u.rval_char=(char))     ; break ;
  310. X      case CTK_UCHAR:  convert_to_fix(v,v->u.rval_uchar=(uchar))   ; break ;
  311. X      case CTK_SHORT:  convert_to_fix(v,v->u.rval_short=(short))   ; break ;
  312. X      case CTK_USHORT: convert_to_fix(v,v->u.rval_ushort=(ushort)) ; break ;
  313. X      case CTK_INT:    convert_to_fix(v,v->u.rval_int=(int))       ; break ;
  314. X      case CTK_UINT:   convert_to_fix(v,v->u.rval_uint=(uint))     ; break ;
  315. X      case CTK_LONG:   convert_to_fix(v,v->u.rval_long=(long))     ; break ;
  316. X      case CTK_ULONG:  convert_to_fix(v,v->u.rval_ulong=(ulong))   ; break ;
  317. X      case CTK_FLOAT:  convert_to_fix(v,v->u.rval_float=(float))   ; break ;
  318. X      case CTK_DOUBLE: convert_to_fix(v,v->u.rval_double=(double)) ; break ;
  319. X      case CTK_PTR:    convert_to_fix(v,
  320. X                        v->u.rval_ptr=(ttarget_ptr)(tptrsize_int)) ; break ;
  321. X      default: duel_assert(0);
  322. X   }
  323. X   v->ctype=t ;
  324. X}
  325. X
  326. X
  327. X/* verify v is numeric, get its rvalue converted to type tout or at least int*/
  328. XLPROC get_numeric_val(tvalue *v,char *op,tctype *tout)
  329. X{
  330. X   if(!ctype_kind_numeric(v->ctype)) 
  331. X       duel_op_error("operand x of '%s' is not numeric",op,v,0);
  332. X   if(!tout) tout=upgrade_small_int_types(v->ctype);   /* upgrade to int etc */
  333. X   convert_scalar_type(v,tout,op);
  334. X}
  335. X
  336. X/*verify v is integral, get its rvalue converted to type tout or at least int*/
  337. XLPROC get_integral_val(tvalue *v,char *op,tctype *tout)
  338. X{
  339. X   if(!ctype_kind_integral(v->ctype)) 
  340. X       duel_op_error("operand x of '%s' is not integral",op,v,0);
  341. X   if(!tout) tout=upgrade_small_int_types(v->ctype);   /* upgrade to int etc */
  342. X   convert_scalar_type(v,tout,op);
  343. X}
  344. X
  345. X/* verify v is integral, return its actual value as 'int' */
  346. XFUNC int duel_get_int_val(tvalue *v,char *op)
  347. X{
  348. X   get_integral_val(v,op,ctype_int);
  349. X   return v->u.rval_int ;
  350. X}
  351. X
  352. X/* verify v is numeric or pointer/array, upgrade type to at least int or ptr
  353. X   and get the rvalue */
  354. XLPROC get_scalar_val(tvalue *v,char *op)
  355. X{
  356. X   if(ctype_kind_ptr_like(v->ctype)) get_rvalue(v,op);
  357. X   else {
  358. X       tctype *t=upgrade_small_int_types(v->ctype);   /* upgrade to int */
  359. X       if(!ctype_kind_numeric(v->ctype)) 
  360. X           duel_op_error("operand x of '%s' is not a scalar",op,v,0);
  361. X       convert_scalar_type(v,t,op);
  362. X   }
  363. X}
  364. X
  365. XLPROC get_pointer_val(tvalue *v,char *op,bool zero_ok)
  366. X{
  367. X   if(ctype_kind_ptr_like(v->ctype)) get_rvalue(v,op);
  368. X   else
  369. X   if(zero_ok && v->ctype->type_kind==CTK_INT && 
  370. X      v->val_kind==VK_RVALUE && v->u.rval_int==0) {
  371. X           v->ctype=ctype_voidptr ;
  372. X           v->u.rval_ptr=0 ;
  373. X   }
  374. X   else duel_op_error("operand x of '%s' is not a pointer",op,v,0);
  375. X}
  376. X
  377. X/* copy one lvalue over the other. This copy is used for assignment,
  378. X * including the assignment of structures and unions.
  379. X * supports unlimited size and error reports when memory access fails.
  380. X */
  381. X
  382. XLPROC copy_lvalues(tvalue *v1,tvalue *v2,char *op)
  383. X{
  384. X    size_t size ;
  385. X    ttarget_ptr to=v1->u.lvalue,from=v2->u.lvalue ;
  386. X    char buf[BUFSIZ] ;
  387. X    duel_assert(v1->val_kind==VK_LVALUE && v2->val_kind==VK_LVALUE);
  388. X    size=v1->ctype->size ;
  389. X    duel_assert(v2->ctype->size==size);
  390. X    while(size!=0) {
  391. X        size_t chunk_size=((size>BUFSIZ)? BUFSIZ:size) ;
  392. X        if(!duel_get_target_bytes(from,buf,chunk_size))
  393. X            duel_op_error("error reading memory (copy) in '%s'",op,v1,v2);
  394. X        if(!duel_put_target_bytes(to,buf,chunk_size))
  395. X            duel_op_error("error writing memory (copy) in '%s'",op,v1,v2);
  396. X        size-=chunk_size ;
  397. X        to+=chunk_size ;
  398. X        from+=chunk_size ;
  399. X    }
  400. X}
  401. X
  402. X/*
  403. X * check that two values have "compatible" types.
  404. X * since structs compiled in different modules are each unique,
  405. X * we settle for comparing the number of references (array/ptr)
  406. X * and then  make sure the same type-kind is used, with the same
  407. X * physical size. 
  408. X * this allows, e.g. struct {short x,y }  and struct {int x}
  409. X * to be considered equal. Possibly one could compare struct/union
  410. X * for member sizes (but not names?!). this however requires to keep
  411. X * track of self references and is not implemented here.
  412. X */
  413. X
  414. XLPROC duel_check_type_eq(tvalue *v1,tvalue *v2,char *op)
  415. X{
  416. X    tctype *t1=v1->ctype, *t2=v2->ctype ;
  417. X    if(t1==ctype_voidptr && ctype_kind_ptr_like(t2) ||
  418. X       t2==ctype_voidptr && ctype_kind_ptr_like(t1) ) return; /*(void*) match*/
  419. X
  420. X    while(ctype_kind_ptr_like(t1) && ctype_kind_ptr_like(t2)) 
  421. X        t1=t1->u.kid, t2=t2->u.kid ;
  422. X    if(t1==t2) return ; /* exact same type */
  423. X    if(t1->type_kind != t2->type_kind || t1->size != t2->size) 
  424. X        duel_op_error("incompatible types for op %s",op,v1,v2);
  425. X}
  426. X
  427. X
  428. X/**************************************************************************
  429. X a set of mid-level functions follow. These actually apply duel/C
  430. X operators to values 
  431. X **************************************************************************/
  432. X
  433. X/* these do pointer+int addition/subtraction of v1,v2 and store result in r.
  434. X * NOTE: r's symbolic value is not set.
  435. X */
  436. X
  437. XLPROC add_offset_to_ptr(tvalue *v1,tvalue *v2,tvalue *r)
  438. X{
  439. X   size_t len ;
  440. X   get_pointer_val(v1,"x+y (ptr add)",FALSE);
  441. X   get_integral_val(v2,"y+x (ptr add)",NULL);
  442. X   r->val_kind=VK_RVALUE ;
  443. X   r->ctype=v1->ctype ;
  444. X   len=v1->ctype->u.kid->size ;
  445. X   if(len==0) duel_op_error("unknown pointer object size for '+' op",0,v1,0);
  446. X   switch(v2->ctype->type_kind) {
  447. X    case CTK_INT:   r->u.rval_ptr =v1->u.rval_ptr +len*v2->u.rval_int  ;break ;
  448. X    case CTK_UINT:  r->u.rval_ptr =v1->u.rval_ptr +len*v2->u.rval_uint ;break ;
  449. X    case CTK_LONG:  r->u.rval_ptr =v1->u.rval_ptr +len*v2->u.rval_long ;break ;
  450. X    case CTK_ULONG: r->u.rval_ptr =v1->u.rval_ptr +len*v2->u.rval_ulong;break ;
  451. X    default: duel_assert(0);
  452. X   }
  453. X}
  454. X
  455. XLPROC sub_offset_from_ptr(tvalue *v1,tvalue *v2,tvalue *r)
  456. X{
  457. X   size_t len ;
  458. X   get_pointer_val(v1,"x-y (ptr sub)",FALSE);
  459. X   get_integral_val(v2,"y-x (ptr sub)",NULL);
  460. X   r->val_kind=VK_RVALUE ;
  461. X   r->ctype=v1->ctype ;
  462. X   len=v1->ctype->u.kid->size ;
  463. X   if(len==0) duel_op_error("unknown pointer object size for '-' op",0,v1,0);
  464. X   switch(v2->ctype->type_kind) {
  465. X    case CTK_INT:   r->u.rval_ptr =v1->u.rval_ptr -len*v2->u.rval_int  ;break ;
  466. X    case CTK_UINT:  r->u.rval_ptr =v1->u.rval_ptr -len*v2->u.rval_uint ;break ;
  467. X    case CTK_LONG:  r->u.rval_ptr =v1->u.rval_ptr -len*v2->u.rval_long ;break ;
  468. X    case CTK_ULONG: r->u.rval_ptr =v1->u.rval_ptr -len*v2->u.rval_ulong;break ;
  469. X    default: duel_assert(0);
  470. X   }
  471. X}
  472. X
  473. X
  474. X/* do addition of v1,v2 and store result in r.
  475. X * NOTE: v1, v2 are destroyed!
  476. X */
  477. XLPROC do_op_add(tvalue *v1,tvalue *v2,tvalue *r)
  478. X{
  479. X   tctype *t=find_numeric_result_type(v1,v2,r,"+");
  480. X   if(ctype_kind_ptr_like(v1->ctype)) {
  481. X       get_integral_val(v2,"pointer+x",NULL);
  482. X       add_offset_to_ptr(v1,v2,r);
  483. X       return ;
  484. X   }
  485. X   if(ctype_kind_ptr_like(v2->ctype)) {
  486. X       get_integral_val(v1,"x+pointer",NULL);
  487. X       add_offset_to_ptr(v2,v1,r);
  488. X       return ;
  489. X   }
  490. X   get_numeric_val(v1,"x+y",t);
  491. X   get_numeric_val(v2,"y+x",t);
  492. X   r->val_kind=VK_RVALUE ;
  493. X   r->ctype=t ;
  494. X   duel_set_symb_val(r,"%s+%s",v1,v2);
  495. X   switch(t->type_kind) {
  496. X    case CTK_INT:   r->u.rval_int  =v1->u.rval_int   +v2->u.rval_int   ;break ;
  497. X    case CTK_UINT:  r->u.rval_uint =v1->u.rval_uint  +v2->u.rval_uint  ;break ;
  498. X    case CTK_LONG:  r->u.rval_long =v1->u.rval_long  +v2->u.rval_long  ;break ;
  499. X    case CTK_ULONG: r->u.rval_ulong=v1->u.rval_ulong +v2->u.rval_ulong ;break ;
  500. X    case CTK_FLOAT: r->u.rval_float=v1->u.rval_float +v2->u.rval_float ;break ;
  501. X    case CTK_DOUBLE:r->u.rval_double=v1->u.rval_double+v2->u.rval_double;break;
  502. X    default: duel_assert(0);
  503. X   }
  504. X}
  505. X
  506. X/* do arithmeric subtraction of v1,v2 and store result in r.
  507. X * v1 and v2 should be of numeric type to begin with.
  508. X * NOTE: v1, v2 are destroyed!
  509. X */
  510. XLPROC do_op_subtract(tvalue *v1,tvalue *v2,tvalue *r)
  511. X{
  512. X   tctype *t=find_numeric_result_type(v1,v2,r,"-");
  513. X   if(ctype_kind_ptr_like(v1->ctype)) {
  514. X       if(ctype_kind_ptr_like(v2->ctype)) {
  515. X           long len ;   /* length must be signed to allow signed p-q result*/
  516. X           get_pointer_val(v1,"x-y",FALSE);
  517. X           get_pointer_val(v2,"x-y",FALSE);
  518. X           duel_check_type_eq(v1,v2,"- (ptr)");
  519. X           /* should compare pointer types */
  520. X           len=v1->ctype->u.kid->size ;
  521. X           if(len<=0) 
  522. X              duel_op_error("illegal object size for op %s","- (ptr)",v1,v2);
  523. X           r->ctype=ctype_ptrdiff_t ;
  524. X           r->u.rval_ptrdiff_t= (v1->u.rval_ptr - v2->u.rval_ptr)/len ;
  525. X           return ;
  526. X       }
  527. X       get_integral_val(v2,"pointer-x",NULL);
  528. X       sub_offset_from_ptr(v1,v2,r);
  529. X       return ;
  530. X   }
  531. X   get_numeric_val(v1,"x-y",t);
  532. X   get_numeric_val(v2,"y-x",t);
  533. X   switch(t->type_kind) {
  534. X    case CTK_INT:   r->u.rval_int  =v1->u.rval_int   - v2->u.rval_int   ;break;
  535. X    case CTK_UINT:  r->u.rval_uint =v1->u.rval_uint  - v2->u.rval_uint  ;break;
  536. X    case CTK_LONG:  r->u.rval_long =v1->u.rval_long  - v2->u.rval_long  ;break;
  537. X    case CTK_ULONG: r->u.rval_ulong=v1->u.rval_ulong - v2->u.rval_ulong ;break;
  538. X    case CTK_FLOAT: r->u.rval_float=v1->u.rval_float - v2->u.rval_float ;break;
  539. X    case CTK_DOUBLE:r->u.rval_double=v1->u.rval_double-v2->u.rval_double;break;
  540. X    default: duel_assert(0);
  541. X   }
  542. X}
  543. X
  544. X/* compare values of v1 and v2, knowing that at least one is a frame-value
  545. X * type. Allows two fvals to be compared, or an fval to be compared
  546. X * to a func (this compares the func at the frame to the given func)
  547. X */
  548. X
  549. XLFUNC bool comp_bin_op_eq_fvals(tvalue *v1,tvalue *v2)
  550. X{
  551. X   bool v1f=v1->val_kind == VK_FVALUE ;
  552. X   bool v2f=v2->val_kind == VK_FVALUE ;
  553. X   int frame_no ;
  554. X   ttarget_ptr frame_func,p ;
  555. X   if(v1f && v2f) return v1->u.fvalue == v2->u.fvalue ; /*cmp frames */
  556. X   if(v1f) { 
  557. X       frame_no = v1->u.fvalue ;
  558. X       get_pointer_val(v2,"frame==x",FALSE) ;
  559. X       if(v2->ctype->u.kid->type_kind!=CTK_FUNC) 
  560. X          duel_op_error("operand x of 'frame=x' not a func pointer",0,v2,0);
  561. X       p=v2->u.rval_ptr ;
  562. X   }
  563. X   else {
  564. X       frame_no = v2->u.fvalue ;
  565. X       get_pointer_val(v1,"x==frame",FALSE) ;
  566. X       if(v1->ctype->u.kid->type_kind!=CTK_FUNC) 
  567. X          duel_op_error("operand x of 'x==frame' not a func pointer",0,v1,0);
  568. X       p=v1->u.rval_ptr ;
  569. X   }
  570. X   frame_func = duel_get_function_for_frame(frame_no);
  571. X   return frame_func == p ; 
  572. X}
  573. X
  574. X
  575. X/* compares of v1,v2 and store result in r.
  576. X * v1 and v2 should be of numeric/pointer type to begin with.
  577. X * NOTE: v1, v2 are destroyed!
  578. X */
  579. X
  580. XLPROC do_op_eq(tvalue *v1,tvalue *v2,tvalue *r)
  581. X{                                                              
  582. X   tctype *t=find_numeric_result_type(v1,v2,r,"==");            
  583. X   r->ctype=ctype_int ;                                        
  584. X   if(v1->val_kind==VK_FVALUE || v2->val_kind==VK_FVALUE) {
  585. X       r->u.rval_int = comp_bin_op_eq_fvals(v1,v2);
  586. X       return ;
  587. X   }
  588. X   if(ctype_kind_ptr_like(v1->ctype) || ctype_kind_ptr_like(v2->ctype)) {
  589. X       get_pointer_val(v1,"x==y",TRUE); 
  590. X       get_pointer_val(v2,"y==x",TRUE);       
  591. X       duel_check_type_eq(v1,v2,"==");          
  592. X       r->u.rval_int = v1->u.rval_ptr == v2->u.rval_ptr ;
  593. X       return ;                                 
  594. X   }                                            
  595. X   get_numeric_val(v1,"x==y",t);                   
  596. X   get_numeric_val(v2,"y==x",t);                   
  597. X   switch(t->type_kind) {                       
  598. X   case CTK_INT:   r->u.rval_int=v1->u.rval_int    == v2->u.rval_int   ;break;
  599. X   case CTK_UINT:  r->u.rval_int=v1->u.rval_uint   == v2->u.rval_uint  ;break;
  600. X   case CTK_LONG:  r->u.rval_int=v1->u.rval_long   == v2->u.rval_long  ;break;
  601. X   case CTK_ULONG: r->u.rval_int=v1->u.rval_ulong  == v2->u.rval_ulong ;break;
  602. X   case CTK_FLOAT: r->u.rval_int=v1->u.rval_float  == v2->u.rval_float ;break;
  603. X   case CTK_DOUBLE:r->u.rval_int=v1->u.rval_double == v2->u.rval_double;break;
  604. X   default: duel_assert(0);                                     
  605. X   }                                                            
  606. X}
  607. X
  608. X
  609. X/* compares of v1,v2 and store result in r.
  610. X * v1 and v2 should be of numeric/pointer type to begin with.
  611. X * NOTE: v1, v2 are destroyed!
  612. X */
  613. X#define mk_func_compare(func,op,sop,xysop,yxsop,nullok) \
  614. XLPROC func(tvalue *v1,tvalue *v2,tvalue *r)                    \
  615. X{                                                              \
  616. X   tctype *t=find_numeric_result_type(v1,v2,r,sop);             \
  617. X   r->ctype=ctype_int ;                                         \
  618. X                                                                \
  619. X   if(ctype_kind_ptr_like(v1->ctype) || ctype_kind_ptr_like(v2->ctype)) { \
  620. X       get_pointer_val(v1,xysop,nullok);                        \
  621. X       get_pointer_val(v2,yxsop,nullok);                        \
  622. X       duel_check_type_eq(v1,v2,sop);                           \
  623. X       r->u.rval_int = v1->u.rval_ptr op v2->u.rval_ptr ;       \
  624. X       return ;                                                 \
  625. X   }                                                            \
  626. X   get_numeric_val(v1,xysop,t);                                 \
  627. X   get_numeric_val(v2,yxsop,t);                                 \
  628. X   switch(t->type_kind) {                                       \
  629. X   case CTK_INT:   r->u.rval_int=v1->u.rval_int    op v2->u.rval_int   ;break;\
  630. X   case CTK_UINT:  r->u.rval_int=v1->u.rval_uint   op v2->u.rval_uint  ;break;\
  631. X   case CTK_LONG:  r->u.rval_int=v1->u.rval_long   op v2->u.rval_long  ;break;\
  632. X   case CTK_ULONG: r->u.rval_int=v1->u.rval_ulong  op v2->u.rval_ulong ;break;\
  633. X   case CTK_FLOAT: r->u.rval_int=v1->u.rval_float  op v2->u.rval_float ;break;\
  634. X   case CTK_DOUBLE:r->u.rval_int=v1->u.rval_double op v2->u.rval_double;break;\
  635. X   default: duel_assert(0);                                     \
  636. X   }                                                            \
  637. X}
  638. X
  639. Xmk_func_compare(do_op_ne,!=,"!=","x!=y","y!=x",TRUE)
  640. Xmk_func_compare(do_op_ge,>=,">=","x>=y","y>=x",FALSE)
  641. Xmk_func_compare(do_op_le,<=,"<=","x<=y","y<=x",FALSE)
  642. Xmk_func_compare(do_op_ls,<, "<", "x<y", "y<x",FALSE)
  643. Xmk_func_compare(do_op_gt,>, ">", "x>y", "y>x",FALSE)
  644. X#undef mk_func_compare 
  645. X
  646. X
  647. X/* do_compare_questionmark -- handle the <? >? etc ops */
  648. X
  649. XLFUNC bool do_compare_questionmark(topcode op,tvalue *v1,tvalue *v2,tvalue *r)
  650. X{
  651. X   tvalue tmp ;
  652. X   tmp= *v1 ; 
  653. X   switch(op) {
  654. X     case OP_EQQ: do_op_eq(v1,v2,r); break ;
  655. X     case OP_NEQ: do_op_ne(v1,v2,r); break ;
  656. X     case OP_GEQ: do_op_ge(v1,v2,r); break ;
  657. X     case OP_LEQ: do_op_le(v1,v2,r); break ;
  658. X     case OP_LSQ: do_op_ls(v1,v2,r); break ;
  659. X     case OP_GTQ: do_op_gt(v1,v2,r); break ;
  660. X   }
  661. X   if(r->u.rval_int==0) return FALSE ;
  662. X   *r=tmp ;
  663. X   return TRUE ;
  664. X}
  665. X
  666. X
  667. X
  668. X/* apply indirection of a pointer.
  669. X * this  is easy, you just force the value to be an rvalue pointer, then 
  670. X * make it into an lvalue with the pointed-to type.
  671. X * useful for (*x x[y] x->y etc)
  672. X * does not setup a symbolic value!
  673. X */
  674. X
  675. X
  676. XLPROC follow_pointer(tvalue *v,char *op,bool nonull)
  677. X{
  678. X   get_pointer_val(v,op,FALSE);
  679. X   if(nonull && v->u.rval_ptr == NULL)
  680. X        duel_op_error("dereference NULL pointer x in '%s'",op,v,0);
  681. X   v->val_kind=VK_LVALUE ;
  682. X   v->u.lvalue=v->u.rval_ptr ;
  683. X   v->ctype=v->ctype->u.kid ;
  684. X}
  685. X
  686. XPROC duel_get_struct_val(tvalue *v,char *op)
  687. X{
  688. X   if(!ctype_kind_struct_like(v->ctype)) 
  689. X       duel_op_error("operand x of '%s' not a sturct/union",op,v,0);
  690. X   duel_assert(v->val_kind==VK_LVALUE);
  691. X}
  692. X
  693. XPROC duel_get_struct_ptr_val(tvalue *v,char *op)
  694. X{
  695. X   follow_pointer(v,op,FALSE);
  696. X   if(!ctype_kind_struct_like(v->ctype)) 
  697. X     duel_op_error("operand x of '%s' not a pointer to sturct/union",op,v,0);
  698. X}
  699. X
  700. XFUNC int duel_get_posint_val(tvalue *v,char *op)    
  701. X{
  702. X    int x ;
  703. X    x=duel_get_int_val(v,op);
  704. X    if(x<0) duel_op_error("operand x of '%s' can not be negative",op,v,0);
  705. X   return x ;
  706. X}
  707. X
  708. X/* indirection operator (*x) */
  709. X
  710. XLPROC do_op_indirection(tvalue *v)
  711. X{
  712. X   follow_pointer(v,"*x",TRUE);
  713. X   duel_set_symb_val(v,"*%s",v,0);
  714. X}
  715. X
  716. X/* address operator (&x) 
  717. X * x must be an lvalue. it is converted into a pointer to the given type,
  718. X * an rvalue.
  719. X */
  720. X
  721. XLPROC do_op_address(tvalue *v)
  722. X{
  723. X   if(v->val_kind != VK_LVALUE) 
  724. X       duel_op_error("operand x of '&x' is not a lvalue",0,v,0);
  725. X   v->val_kind=VK_RVALUE ;
  726. X   v->u.rval_ptr=v->u.lvalue ;
  727. X   v->ctype=duel_mkctype_ptr(v->ctype);
  728. X   duel_set_symb_val(v,"&%s",v,0);
  729. X}
  730. X
  731. XLPROC do_op_index(tvalue *v1,tvalue *v2,tvalue *r)
  732. X{
  733. X    get_pointer_val(v1,"x[y]",FALSE);
  734. X    get_integral_val(v2,"y[x]",NULL);
  735. X    add_offset_to_ptr(v1,v2,r);
  736. X    follow_pointer(r,"[]",TRUE);
  737. X    duel_set_symb_val(r,"%s[%s]",v1,v2);
  738. X}
  739. X
  740. X
  741. X/* do arithmeric multiply of v1,v2 and store result in r.
  742. X * NOTE: v1, v2 are destroyed!
  743. X */
  744. XLPROC do_op_multiply(tvalue *v1,tvalue *v2,tvalue *r)
  745. X{
  746. X   tctype *t=find_numeric_result_type(v1,v2,r,"*");
  747. X   get_numeric_val(v1,"x*y",t);
  748. X   get_numeric_val(v2,"y*x",t);
  749. X   r->val_kind=VK_RVALUE ;
  750. X   r->ctype=t ;
  751. X   duel_set_symb_val(r,"%s*%s",v1,v2);
  752. X   switch(t->type_kind) {
  753. X    case CTK_INT:   r->u.rval_int   =v1->u.rval_int   * v2->u.rval_int  ;break;
  754. X    case CTK_UINT:  r->u.rval_uint  =v1->u.rval_uint  * v2->u.rval_uint ;break;
  755. X    case CTK_LONG:  r->u.rval_long  =v1->u.rval_long  * v2->u.rval_long ;break;
  756. X    case CTK_ULONG: r->u.rval_ulong =v1->u.rval_ulong * v2->u.rval_ulong;break;
  757. X    case CTK_FLOAT: r->u.rval_float =v1->u.rval_float * v2->u.rval_float;break;
  758. X    case CTK_DOUBLE:r->u.rval_double=v1->u.rval_double*v2->u.rval_double;break;
  759. X    default: duel_assert(0);
  760. X   }
  761. X}
  762. X
  763. X/* do numeric divide of v1,v2 and store result in r.
  764. X * v1 and v2 should be of numeric type to begin with.
  765. X * NOTE: v1, v2 are destroyed!
  766. X */
  767. XLPROC do_op_divide(tvalue *v1,tvalue *v2,tvalue *r)
  768. X{
  769. X   tctype *t=find_numeric_result_type(v1,v2,r,"/");
  770. X   get_numeric_val(v1,"x/y",t);
  771. X   get_numeric_val(v2,"y/x",t);
  772. X   switch(t->type_kind) {
  773. X    case CTK_INT:   if(v2->u.rval_int==0) goto div_err;
  774. X                    r->u.rval_int   =v1->u.rval_int  / v2->u.rval_int   ;break;
  775. X    case CTK_UINT:  if(v2->u.rval_uint==0) goto div_err;
  776. X                    r->u.rval_uint  =v1->u.rval_uint / v2->u.rval_uint  ;break;
  777. X    case CTK_LONG:  if(v2->u.rval_long==0) goto div_err;
  778. X                    r->u.rval_long  =v1->u.rval_long / v2->u.rval_long  ;break;
  779. X    case CTK_ULONG: if(v2->u.rval_ulong==0) goto div_err;
  780. X                    r->u.rval_ulong =v1->u.rval_ulong/ v2->u.rval_ulong ;break;
  781. X    case CTK_FLOAT: if(v2->u.rval_float==0.0) goto div_err;
  782. X                    r->u.rval_float =v1->u.rval_float/ v2->u.rval_float ;break;
  783. X    case CTK_DOUBLE:if(v2->u.rval_double==0.0) goto div_err;
  784. X                    r->u.rval_double=v1->u.rval_double/v2->u.rval_double;break;
  785. X    default: duel_assert(0);
  786. X   }
  787. X   return ;
  788. Xdiv_err: duel_op_error("division by zero",0,v1,v2);
  789. X}
  790. X
  791. X
  792. X/* do arithmeric reminder of v1,v2 and store result in r.
  793. X * NOTE: v1, v2 are destroyed!
  794. X */
  795. XLPROC do_op_reminder(tvalue *v1,tvalue *v2,tvalue *r)
  796. X{
  797. X   tctype *t=find_numeric_result_type(v1,v2,r,"%");
  798. X   get_integral_val(v1,"x%y",t);
  799. X   get_integral_val(v2,"y%x",t);
  800. X   switch(t->type_kind) {
  801. X    case CTK_INT:    if(v2->u.rval_int==0) goto div_err;
  802. X               r->u.rval_int   = v1->u.rval_int   % v2->u.rval_int    ; break ;
  803. X    case CTK_UINT:   if(v2->u.rval_uint==0) goto div_err;
  804. X               r->u.rval_uint  = v1->u.rval_uint  % v2->u.rval_uint   ; break ;
  805. X    case CTK_LONG:   if(v2->u.rval_long==0) goto div_err;
  806. X               r->u.rval_long  = v1->u.rval_long  % v2->u.rval_long   ; break ;
  807. X    case CTK_ULONG:  if(v2->u.rval_ulong==0) goto div_err;
  808. X               r->u.rval_ulong = v1->u.rval_ulong % v2->u.rval_ulong  ; break ;
  809. X    default: duel_assert(0);
  810. X   }
  811. X   return ;
  812. Xdiv_err: duel_op_error("reminder modulo zero",0,v1,v2);
  813. X}
  814. X
  815. X/* do arithmeric or (bitwise) of v1,v2 and store result in r.
  816. X * NOTE: v1, v2 are destroyed!
  817. X */
  818. XLPROC do_op_or(tvalue *v1,tvalue *v2,tvalue *r)
  819. X{
  820. X   tctype *t=find_numeric_result_type(v1,v2,r,"|");
  821. X   get_integral_val(v1,"x|y",t);
  822. X   get_integral_val(v2,"y|x",t);
  823. X   switch(t->type_kind) {
  824. X    case CTK_INT:  r->u.rval_int  = v1->u.rval_int   | v2->u.rval_int  ; break;
  825. X    case CTK_UINT: r->u.rval_uint = v1->u.rval_uint  | v2->u.rval_uint ; break;
  826. X    case CTK_LONG: r->u.rval_long = v1->u.rval_long  | v2->u.rval_long ; break;
  827. X    case CTK_ULONG:r->u.rval_ulong= v1->u.rval_ulong | v2->u.rval_ulong; break;
  828. X    default: duel_assert(0);
  829. X   }
  830. X   return ;
  831. X}
  832. X
  833. X/* do arithmeric and (bitwise) of v1,v2 and store result in r.
  834. X * NOTE: v1, v2 are destroyed!
  835. X */
  836. XLPROC do_op_and(tvalue *v1,tvalue *v2,tvalue *r)
  837. X{
  838. X   tctype *t=find_numeric_result_type(v1,v2,r,"&");
  839. X   get_integral_val(v1,"x&y",t);
  840. X   get_integral_val(v2,"y&x",t);
  841. X   switch(t->type_kind) {
  842. X    case CTK_INT:  r->u.rval_int  = v1->u.rval_int   & v2->u.rval_int  ; break;
  843. X    case CTK_UINT: r->u.rval_uint = v1->u.rval_uint  & v2->u.rval_uint ; break;
  844. X    case CTK_LONG: r->u.rval_long = v1->u.rval_long  & v2->u.rval_long ; break;
  845. X    case CTK_ULONG:r->u.rval_ulong= v1->u.rval_ulong & v2->u.rval_ulong; break;
  846. X    default: duel_assert(0);
  847. X   }
  848. X}
  849. X
  850. X/* do arithmeric xor (bitwise) of v1,v2 and store result in r.
  851. X * NOTE: v1, v2 are destroyed!
  852. X */
  853. XLPROC do_op_xor(tvalue *v1,tvalue *v2,tvalue *r)
  854. X{
  855. X   
  856. X   tctype *t=find_numeric_result_type(v1,v2,r,"^");
  857. X   get_integral_val(v1,"x^y",t);
  858. X   get_integral_val(v2,"y^x",t);
  859. X   switch(t->type_kind) {
  860. X    case CTK_INT:  r->u.rval_int  = v1->u.rval_int  ^ v2->u.rval_int  ; break ;
  861. X    case CTK_UINT: r->u.rval_uint = v1->u.rval_uint ^ v2->u.rval_uint ; break ;
  862. X    case CTK_LONG: r->u.rval_long = v1->u.rval_long ^ v2->u.rval_long ; break ;
  863. X    case CTK_ULONG:r->u.rval_ulong= v1->u.rval_ulong^ v2->u.rval_ulong; break ;
  864. X    default: duel_assert(0);
  865. X   }
  866. X   return ;
  867. X}
  868. X
  869. X/* do arithmeric leftshift of v1,v2 and store result in r.
  870. X * v1 and v2 should be of numeric type to begin with.
  871. X * NOTE: v1, v2 are destroyed!
  872. X */
  873. XLPROC do_op_leftshift(tvalue *v1,tvalue *v2,tvalue *r)
  874. X{
  875. X   int by;
  876. X   get_integral_val(v1,"x<<y",NULL);
  877. X   by=duel_get_int_val(v2,"y<<x");
  878. X   r->val_kind=VK_RVALUE ;
  879. X   r->ctype=v1->ctype ;
  880. X   duel_set_symb_val(r,"%s<<%s",v1,v2);
  881. X   switch(v1->ctype->type_kind) {
  882. X    case CTK_INT:    r->u.rval_int   = v1->u.rval_int   << by ; break ;
  883. X    case CTK_UINT:   r->u.rval_uint  = v1->u.rval_uint  << by ; break ;
  884. X    case CTK_LONG:   r->u.rval_long  = v1->u.rval_long  << by ; break ;
  885. X    case CTK_ULONG:  r->u.rval_ulong = v1->u.rval_ulong << by ; break ;
  886. X    default: duel_assert(0);
  887. X   }
  888. X}
  889. X
  890. X/* do arithmeric rightshift of v1,v2 and store result in r.
  891. X * v1 and v2 should be of numeric type to begin with.
  892. X * NOTE: v1, v2 are destroyed!
  893. X */
  894. XLPROC do_op_rightshift(tvalue *v1,tvalue *v2,tvalue *r)
  895. X{
  896. X   int by ;
  897. X   get_integral_val(v1,"x>>y",NULL);
  898. X   by=duel_get_int_val(v2,"y>>x");
  899. X   r->val_kind=VK_RVALUE ;
  900. X   r->ctype=v1->ctype ;
  901. X   duel_set_symb_val(r,"%s>>%s",v1,v2);
  902. X   switch(v1->ctype->type_kind) {
  903. X    case CTK_INT:    r->u.rval_int   = v1->u.rval_int   >> by ; break ;
  904. X    case CTK_UINT:   r->u.rval_uint  = v1->u.rval_uint  >> by ; break ;
  905. X    case CTK_LONG:   r->u.rval_long  = v1->u.rval_long  >> by ; break ;
  906. X    case CTK_ULONG:  r->u.rval_ulong = v1->u.rval_ulong >> by ; break ;
  907. X    default: duel_assert(0);
  908. X   }
  909. X}
  910. X
  911. X/* do arithmeric not of v (!v) */
  912. XLPROC do_op_not(tvalue *v)
  913. X{
  914. X   get_scalar_val(v,"!x");
  915. X   duel_set_symb_val(v,"!%s",v,0);
  916. X   switch(v->ctype->type_kind) {
  917. X    case CTK_PTR:    v->u.rval_int   =  ! v->u.rval_ptr    ; break ;
  918. X    case CTK_INT:    v->u.rval_int   =  ! v->u.rval_int    ; break ;
  919. X    case CTK_UINT:   v->u.rval_int   =  ! v->u.rval_uint   ; break ;
  920. X    case CTK_LONG:   v->u.rval_int   =  ! v->u.rval_long   ; break ;
  921. X    case CTK_ULONG:  v->u.rval_int   =  ! v->u.rval_ulong  ; break ;
  922. X    case CTK_FLOAT:  v->u.rval_int   =  ! v->u.rval_float  ; break ;
  923. X    case CTK_DOUBLE: v->u.rval_int   =  ! v->u.rval_double ; break ;
  924. X    default: duel_assert(0);
  925. X   }
  926. X   v->ctype=ctype_int ;         /* always returns an int */
  927. X}
  928. X
  929. X/* do bit-complement of v (~v) */
  930. XLPROC do_op_complement(tvalue *v)
  931. X{
  932. X   get_integral_val(v,"~x",NULL);
  933. X   duel_set_symb_val(v,"~%s",v,0);
  934. X   switch(v->ctype->type_kind) {
  935. X    case CTK_INT:    v->u.rval_int   =  ~ v->u.rval_int    ; break ;
  936. X    case CTK_UINT:   v->u.rval_uint  =  ~ v->u.rval_uint   ; break ;
  937. X    case CTK_LONG:   v->u.rval_long  =  ~ v->u.rval_long   ; break ;
  938. X    case CTK_ULONG:  v->u.rval_ulong =  ~ v->u.rval_ulong  ; break ;
  939. X    default: duel_assert(0);
  940. X   }
  941. X}
  942. X
  943. X /* do arithmeric minus of v (-v) */
  944. XLPROC do_op_minus(tvalue *v)
  945. X{
  946. X   get_numeric_val(v,"-x",NULL);
  947. X   duel_set_symb_val(v,"-%s",v,0);
  948. X   switch(v->ctype->type_kind) {
  949. X    case CTK_INT:    v->u.rval_int   =  - v->u.rval_int    ; break ;
  950. X    case CTK_UINT:   v->u.rval_uint  =  - v->u.rval_uint   ; break ;
  951. X    case CTK_LONG:   v->u.rval_long  =  - v->u.rval_long   ; break ;
  952. X    case CTK_ULONG:  v->u.rval_ulong =  - v->u.rval_ulong  ; break ;
  953. X    case CTK_FLOAT:  v->u.rval_float =  - v->u.rval_float  ; break ;
  954. X    case CTK_DOUBLE: v->u.rval_double=  - v->u.rval_double ; break ;
  955. X    default: duel_assert(0);
  956. X   }
  957. X}
  958. X
  959. X/* do sizeif(exp) - simply return the size of the exp's type */
  960. XLPROC do_op_sizeofexp(tvalue *v)
  961. X{
  962. X    v->val_kind=VK_RVALUE ;
  963. X    v->u.rval_size_t=v->ctype->size ;
  964. X    v->ctype=ctype_size_t ;
  965. X    duel_set_symb_val(v,"sizeof(%s)",v,0);
  966. X}
  967. X
  968. XLPROC do_op_assignment(tvalue *v1,tvalue *v2,tvalue *r,char *op)
  969. X{
  970. X    if(v1->val_kind!=VK_LVALUE && v1->val_kind!=VK_BVALUE)
  971. X        duel_op_error("left size not an lvalue for operator '%s'",op,v1,0);
  972. X
  973. X    if(ctype_kind_struct_like(v1->ctype)) {
  974. X        duel_check_type_eq(v1,v2,op);
  975. X        copy_lvalues(v1,v2,op);
  976. X        *r= *v2 ;  /* return the result as an lvalue. this means (x1=x2)=x3
  977. X                      is legal for struct, unlike ansi-c. */
  978. X        return ;
  979. X    }
  980. X    if(ctype_kind_numeric(v1->ctype)) get_numeric_val(v2,op,v1->ctype);
  981. X    else
  982. X    if(v1->ctype->type_kind==CTK_PTR) {
  983. X      get_pointer_val(v2,op,TRUE);
  984. X      duel_check_type_eq(v1,v2,op);
  985. X    }
  986. X    else duel_op_error("bad left operand type for operator '%s'",op,v1,0);
  987. X    put_rvalue(v1,v2,op);
  988. X    *r= *v2 ;
  989. X}
  990. X
  991. XLPROC do_op_increment(tvalue *v,char *op,int inc,bool postfix)
  992. X{
  993. X    tvalue lvalue_v,oldv ;
  994. X    char s[80] ;
  995. X    if(v->val_kind!=VK_LVALUE) 
  996. X      duel_op_error("operand of '%s' must be an lvalue",op,v,0);
  997. X    lvalue_v= *v ;
  998. X    if(v->ctype->type_kind==CTK_PTR) get_pointer_val(v,op,FALSE);
  999. X    else get_integral_val(v,op,0);
  1000. X    oldv= *v ;
  1001. X
  1002. X   switch(v->ctype->type_kind) {
  1003. X    case CTK_INT:   v->u.rval_int   +=  inc ; break ;
  1004. X    case CTK_UINT:  v->u.rval_uint  +=  inc ; break ;
  1005. X    case CTK_LONG:  v->u.rval_long  +=  inc ; break ;
  1006. X    case CTK_ULONG: v->u.rval_ulong +=  inc ; break ;
  1007. X    case CTK_PTR:   v->u.rval_ptr   +=  inc*v->ctype->u.kid->size ; break;
  1008. X    default: duel_assert(0);
  1009. X   }
  1010. X   convert_scalar_type(v,lvalue_v.ctype,op);  /* back to the original type */
  1011. X   put_rvalue(&lvalue_v,v,op);
  1012. X   if(postfix) {                        /* if prefix, keep v and its sym val*/
  1013. X       *v= oldv ;
  1014. X       convert_scalar_type(v,lvalue_v.ctype,op);  /* back to original type */
  1015. X       sprintf(s,"%%s%s",op);
  1016. X       duel_set_symb_val(v,s,v,0);
  1017. X   }
  1018. X}
  1019. X
  1020. X/* unary op 'frame(n)' converts int n to a "frame type" */
  1021. XLPROC do_op_frame(tvalue *v)
  1022. X{
  1023. X   int f=duel_get_int_val(v,"frame(x)");
  1024. X   if(f<0 || f>=duel_get_frames_number()) 
  1025. X       duel_gen_error("Frame number too big",0);
  1026. X   v->val_kind=VK_FVALUE ;
  1027. X   v->ctype=ctype_int ;
  1028. X   v->u.fvalue=f ;
  1029. X   duel_set_symb_val(v,"frame(%s)",v,0);
  1030. X}
  1031. X
  1032. X/* unary op '(x)'. this only add parenthesis to the symbolic value, if needed*/
  1033. X
  1034. XLPROC do_op_parenthesis(tvalue *v)
  1035. X{
  1036. X    char *s=v->symb_val ;
  1037. X    int l=strlen(s);
  1038. X    if(s[0]=='(' && s[l-1]==')') return ; /* val is (x) dont make it ((x)) */
  1039. X    while(*s!=0 && (isalnum(*s) || *s=='_')) s++ ; /* find first non alnum*/
  1040. X    if(*s==0) return ;  /* no need for (x) if x is a name or constant number */
  1041. X    duel_set_symb_val(v,"(%s)",v,0); 
  1042. X}
  1043. X
  1044. X/***********************************************************************
  1045. X High-level functions, major entries to this module, evaluate a node
  1046. X with a standard (single value) result
  1047. X ***********************************************************************/
  1048. X
  1049. X
  1050. X/* standardize a paramater to a function call according to the standard rules.
  1051. X * we currently don't support union/struct paramater passing
  1052. X */
  1053. X
  1054. XPROC duel_standardize_func_parm(tvalue *p)
  1055. X{
  1056. X   /* convert paramater into "standard" function calling */   
  1057. X   if(ctype_kind_integral(p->ctype)) get_integral_val(p,"f()",NULL);
  1058. X   else 
  1059. X   if(ctype_kind_numeric(p->ctype))     /* float, double to double */
  1060. X       convert_scalar_type(p,ctype_double,"f()");
  1061. X   else
  1062. X   if(ctype_kind_ptr_like(p->ctype)) get_pointer_val(p,"f()",FALSE);
  1063. X   else
  1064. X       duel_op_error("unsupported paramater type",0,p,0);
  1065. X}
  1066. X
  1067. X
  1068. X/* given a function (or pointer), find the first (top-most) frame that
  1069. X * the function is active in, and return the FVALUE  for it
  1070. X */
  1071. XPROC duel_find_func_frame(tvalue *v,char *op)
  1072. X{
  1073. X    int i, frames_no=duel_get_frames_number();
  1074. X    get_pointer_val(v,op,FALSE);
  1075. X
  1076. X    for(i=0 ; i<frames_no ; i++) {
  1077. X        ttarget_ptr frame_func = duel_get_function_for_frame(i);
  1078. X        if(frame_func==v->u.rval_ptr) {
  1079. X            v->val_kind=VK_FVALUE ;
  1080. X            v->ctype=ctype_int ;
  1081. X            v->u.rval_int=i ;
  1082. X            return ;
  1083. X        }
  1084. X    }
  1085. X    duel_op_error("func x is not on the call stack for operator '%s'",op,v,0);
  1086. X}
  1087. X
  1088. X
  1089. X/* compute the n'th result of v1..v2 operator.
  1090. X * result is returned in r, returns false if there isnt an nth result
  1091. X * v1,v2 are converted to integer values (but can be used to call this 
  1092. X * function again. errors are reported if they arenot integral.
  1093. X */
  1094. X
  1095. XFUNC bool duel_do_op_to(tvalue *v1,tvalue *v2,int n,tvalue *r)
  1096. X{
  1097. X    int a,b,inc,x ;
  1098. X    char *p,*fmt ;
  1099. X
  1100. X    if(!v1) { a=0 ; b=duel_get_int_val(v2,"..x")-1 ; }
  1101. X    else if(!v2) { a=duel_get_int_val(v1,"x.."); b=INT_MAX ; }
  1102. X    else { a=duel_get_int_val(v1,"x..y"); b=duel_get_int_val(v2,"x..y"); }
  1103. X    if(a<=b) inc=1 ;
  1104. X    else inc= -1 ;
  1105. X    x=a+n*inc ;
  1106. X    if(inc>0 && x>b || inc<0 && x<b) return FALSE ;
  1107. X
  1108. X    r->val_kind=VK_RVALUE ;
  1109. X    r->ctype=ctype_int ;
  1110. X    r->u.rval_int=x ;
  1111. X    if(v1) p=v1->symb_val ;
  1112. X    else   p=v2->symb_val ;
  1113. X    if(     *p=='0'  && p[1]=='x'  || p[1]=='X')  fmt="0x%x" ;
  1114. X    else if(*p=='0'  && p[1]>='0'  && p[1]<='7')  fmt="0%o"  ;
  1115. X    else if(*p=='\'' && isascii(x) && isprint(x)) fmt="'%c'" ;
  1116. X    else                                          fmt="%d"   ;
  1117. X    sprintf(r->symb_val,fmt,x);
  1118. X    return TRUE ;
  1119. X}
  1120. X
  1121. X/* convert value to True/False and return it 
  1122. X * in case of an illegal operand, indicateds the operator is (op)
  1123. X * main use: in operators '&&' '||' and 'if'
  1124. X */
  1125. X
  1126. XFUNC bool duel_mk_logical(tvalue *v,char *op)
  1127. X{
  1128. X   get_scalar_val(v,op);                /* verify v is scalar */
  1129. X   do_op_not(v);                        /* convert and force 0 or 1 */
  1130. X   v->u.rval_int = !v->u.rval_int ;
  1131. X   sprintf(v->symb_val,"%d",v->u.rval_int);
  1132. X   return(v->u.rval_int);
  1133. X}
  1134. X
  1135. X/* cast the value v into type t. */
  1136. X
  1137. XPROC duel_do_cast(tctype *tout,tvalue *v)
  1138. X{
  1139. X    tctype *t=v->ctype ;
  1140. X    if(ctype_kind_scalar(t) && ctype_kind_scalar(tout)) {
  1141. X        if(tout->type_kind==CTK_ARRAY) 
  1142. X            duel_gen_error("casting to an array type is illegal",0);
  1143. X        else convert_scalar_type(v,tout,"(cast) x");
  1144. X    }
  1145. X    else duel_op_error("illegal type conversion in cast op",0,v,0);
  1146. X}
  1147. X
  1148. X
  1149. X/* apply unary oprand op to the given value. The original value is 
  1150. X * destoryed (of course)
  1151. X */
  1152. X
  1153. XPROC duel_apply_unary_op(topcode op,tvalue *v)
  1154. X{
  1155. X   switch(op) {
  1156. X      case '(':  do_op_parenthesis(v);            break ;
  1157. X      case '{':  duel_sprint_scalar_value(v->symb_val,v);break ;
  1158. X      case '-':  do_op_minus(v);                  break ;
  1159. X      case '!':  do_op_not(v);                    break ;
  1160. X      case '*':  do_op_indirection(v);            break ;
  1161. X      case '~':  do_op_complement(v);             break ;
  1162. X      case '&':  do_op_address(v);                break ;
  1163. X      case OP_SIZ: do_op_sizeofexp(v);            break ;
  1164. X      case OP_INC: do_op_increment(v,"++",1,FALSE); break ;
  1165. X      case OP_DEC: do_op_increment(v,"--",-1,FALSE); break ;
  1166. X      case OP_FRAME: do_op_frame(v);    break ;
  1167. X      default: duel_assert(0);
  1168. X   }
  1169. X}
  1170. X
  1171. XPROC duel_apply_post_unary_op(topcode op,tvalue *v)
  1172. X{
  1173. X   switch(op) {
  1174. X      case OP_INC: do_op_increment(v,"++",1,TRUE); break ;
  1175. X      case OP_DEC: do_op_increment(v,"--",-1,TRUE); break ;
  1176. X      default: duel_assert(0);
  1177. X   }
  1178. X}
  1179. X
  1180. X
  1181. X/* apply_bin_op -- apply the operator op to the values v1 v2 and return
  1182. X *                 the result in r. the bin op is a 'regular' one, like
  1183. X *                 '+', '*', etc. in the C language.
  1184. X * note: v1,v2 are destroyed
  1185. X * returns: true if a value has been produced, false otherwise. 
  1186. X *       (ops like '+' always return true. ops like '<=?' also return false)
  1187. X */
  1188. X
  1189. XFUNC bool duel_apply_bin_op(topcode op,tvalue *v1,tvalue *v2,tvalue *r)
  1190. X{
  1191. X  switch(op) {
  1192. X   case '[': do_op_index(v1,v2,r); break ;
  1193. X   case '+':  do_op_add(v1,v2,r);      break ;
  1194. X   case '-':  do_op_subtract(v1,v2,r); break ;
  1195. X   case '*':  do_op_multiply(v1,v2,r); break ;
  1196. X   case '/':  do_op_divide(v1,v2,r);   break ;
  1197. X   case '%':  do_op_reminder(v1,v2,r); break ;
  1198. X   case '|':  do_op_or(v1,v2,r);       break;
  1199. X   case '&':  do_op_and(v1,v2,r);      break ;
  1200. X   case '^':  do_op_xor(v1,v2,r); break ;
  1201. X   case OP_LSH: do_op_leftshift(v1,v2,r); break ;
  1202. X   case OP_RSH: do_op_rightshift(v1,v2,r); break ;
  1203. X   case OP_EQ:  do_op_eq(v1,v2,r); break ;
  1204. X   case OP_NE:  do_op_ne(v1,v2,r); break ;
  1205. X   case OP_GE:  do_op_ge(v1,v2,r); break ;
  1206. X   case OP_LE:  do_op_le(v1,v2,r); break ;
  1207. X   case '<':    do_op_ls(v1,v2,r); break ;
  1208. X   case '>':    do_op_gt(v1,v2,r); break ;
  1209. X   case OP_EQQ: 
  1210. X   case OP_NEQ:
  1211. X   case OP_GEQ:
  1212. X   case OP_LEQ:
  1213. X   case OP_LSQ:
  1214. X   case OP_GTQ: return do_compare_questionmark(op,v1,v2,r); 
  1215. X   case '=':    do_op_assignment(v1,v2,r,"="); break ;
  1216. X   default: duel_assert(0);
  1217. X  }
  1218. X  return TRUE ;
  1219. X}
  1220. SHAR_EOF
  1221. $TOUCH -am 0113165193 src/evalops.c &&
  1222. chmod 0644 src/evalops.c ||
  1223. echo "restore of src/evalops.c failed"
  1224. set `wc -c src/evalops.c`;Wc_c=$1
  1225. if test "$Wc_c" != "45286"; then
  1226.     echo original size 45286, current size $Wc_c
  1227. fi
  1228. # ============= src/error.c ==============
  1229. echo "x - extracting src/error.c (Text)"
  1230. sed 's/^X//' << 'SHAR_EOF' > src/error.c &&
  1231. X/*   DUEL - A Very High Level Debugging Langauge.  */
  1232. X/*   Public domain code                       */
  1233. X/*   Written by Michael Golan mg@cs.princeton.edu  */
  1234. X/*$Header: /tmp_mnt/n/fs/grad2/mg/duel/RCS/error.c,v 1.4 93/01/12 21:35:31 mg Exp $*/
  1235. X
  1236. X/* display errors in a neat way */
  1237. X
  1238. X/*
  1239. X * $Log:    error.c,v $
  1240. X * Revision 1.4  93/01/12  21:35:31  mg
  1241. X * cleanup and set for release
  1242. X * 
  1243. X */
  1244. X
  1245. X#include "duel.h"
  1246. X
  1247. Xstatic tnode *curr_eval_node ;    /* current node being evaluated */
  1248. Xstatic  char *curr_inputstr ;   /* current input string being eval */
  1249. X
  1250. X/* indicate the active node where an operator is now evaluated.
  1251. X * if an error occurs, this marker is used to tell the user where
  1252. X * the error is located.
  1253. X * return previous setup to caller, so it can be restored.
  1254. X */
  1255. X
  1256. XFUNC tnode* duel_set_eval_loc(tnode *n)
  1257. X{
  1258. X    tnode *prev=curr_eval_node ;
  1259. X    curr_eval_node=n ;
  1260. X    return prev ;
  1261. X}
  1262. X
  1263. X/* indicate the current input string which is evaluated 
  1264. X * (intended for future versions with multiple input strings)
  1265. X */
  1266. X
  1267. XFUNC char* duel_set_input_string(char *s)
  1268. X{
  1269. X   char *prev=curr_inputstr ;
  1270. X   curr_inputstr=s ;
  1271. X   return prev ;
  1272. X}
  1273. X/* display source position for errors, based on current node being eval'ed */
  1274. X
  1275. XLPROC print_src_pos(void)
  1276. X{
  1277. X    int src_pos=0 ;
  1278. X    int i ;
  1279. X    if(curr_eval_node) src_pos=curr_eval_node->src_pos ;
  1280. X    printf("Error:   %s\n",curr_inputstr) ;
  1281. X    printf("         ") ;
  1282. X    for(i=0 ; i<src_pos ; i++) printf("-");
  1283. X    printf("^-- ");
  1284. X}
  1285. X
  1286. X/* called for errors that are results of bad user input (syntax/sematics),
  1287. X * e.g. an illegal variable name, etc
  1288. X * the message is printed as a format string for 'op'.
  1289. X * the error location in the source is printed based on the current eval node,
  1290. X * and the value of the given operands are displayed.
  1291. X */
  1292. X
  1293. XPROC duel_op_error(char *mesg,char *op,tvalue *v1,tvalue *v2)
  1294. X{
  1295. X    char s[160] ;
  1296. X    print_src_pos();
  1297. X    printf(mesg,op);
  1298. X    printf("\n");
  1299. X    if(v1) {
  1300. X      printf("operand%s ``%s'' ",(v2!=0)? "1":"",v1->symb_val);
  1301. X      printf("\t-- type: ");
  1302. X      duel_print_type(v1->ctype,1);
  1303. X      duel_sprint_scalar_value(s,v1);
  1304. X      printf("\n\t\t-- value: %s\n",s);
  1305. X    }
  1306. X    if(v2) {
  1307. X      printf("operand%s ``%s'' ",(v1!=0)? "2":"",v2->symb_val);
  1308. X      printf("\t-- type: ");
  1309. X      duel_print_type(v2->ctype,1);
  1310. X      duel_sprint_scalar_value(s,v2);
  1311. X      printf("\n\t\t-- value: %s\n",s);
  1312. X    }
  1313. X    
  1314. X    duel_abort();
  1315. X}
  1316. X
  1317. X/* handle a genral error, no value (operand) is involved.
  1318. X * location (node) is still displayed
  1319. X */
  1320. X
  1321. XPROC duel_gen_error(char *mesg,char *arg1)
  1322. X{
  1323. X    print_src_pos();
  1324. X    printf(mesg,arg1);
  1325. X    printf("\n");
  1326. X    duel_abort();
  1327. X}
  1328. X
  1329. X/* handle fatal messages */
  1330. X
  1331. XPROC duel_fatal(char *msg)
  1332. X{
  1333. X   printf("Fatal Duel error: %s\n",msg);
  1334. X   duel_abort();
  1335. X}
  1336. X
  1337. X
  1338. SHAR_EOF
  1339. $TOUCH -am 0113165193 src/error.c &&
  1340. chmod 0644 src/error.c ||
  1341. echo "restore of src/error.c failed"
  1342. set `wc -c src/error.c`;Wc_c=$1
  1343. if test "$Wc_c" != "2715"; then
  1344.     echo original size 2715, current size $Wc_c
  1345. fi
  1346. echo "End of part 5, continue with part 6"
  1347. exit 0
  1348.