home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume7 / basic / part01 next >
Text File  |  1986-12-03  |  56KB  |  1,999 lines

  1. Subject:  v07i073:  A BASIC Interpreter, Part01/06
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: phil@Cs.Ucl.AC.UK
  6. Mod.sources: Volume 7, Issue 73
  7. Archive-name: basic/Part01
  8.  
  9. [  This code ran fine on my Pyramid98x.  --r$  ]
  10.  
  11. # Shar file shar01 (of 6)
  12. #
  13. # This is a shell archive containing the following files :-
  14. #    README
  15. #    assist.c
  16. #    bas.h
  17. #    bas1.c
  18. # ------------------------------
  19. # This is a shell archive, shar, format file.
  20. # To unarchive, feed this text into /bin/sh in the directory
  21. # you wish the files to be in.
  22.  
  23. echo Makeing subdirs 1>&2
  24. mkdir pdp11 cursor vax pyramid docs m68000
  25. echo x - README 1>&2
  26. sed 's/^X//' > README << 'End of README'
  27. XBASIC (an Interpreter)
  28. X----------------------
  29. X
  30. XThis directory contains the source of my BASIC interpreter. 
  31. XIt was originally started when I was a student as a 2ndyr project, I
  32. Xcontinued to work on it afterwards every once in a while, putting
  33. Xvarious extra facilities into it as I went along. 
  34. XThe interpreter is based on a combination of Microsoft level 5 basic and
  35. Xand RT11's MU-Basic with a smattering of Basic Plus in there for good
  36. Xmeasure. The rational behind this was that these were the versions I
  37. Xfirst learned to program in (many years ago). There are some parts of
  38. Xthe system I would redo again (especially the file handling - which is
  39. Xonly just workable) but I don't have the time. I'm sure the
  40. Xdocumentation does not have all the latest facilities in but most of
  41. Xthem can be worked out from the source code.
  42. X
  43. XThis code is being put in the Public Domain since I will soon loose
  44. Xnetwork connectivity (I am leaving my job) and I don't particularly want
  45. Xto sell it. This system does not contain any proprietary software. All
  46. Xthe algorithms are original or come from publicly available sources.
  47. X
  48. XThere are no licensing restrictions on this code or documentation at
  49. Xall. I only ask that you give appropriate credit to the author.
  50. X
  51. XBuilding the system
  52. X-------------------
  53. X
  54. XThis system has been built and tested on a Vax running 4.2 (4.1) on a
  55. Xpdp11 (with and without floating point hardware ) running V6 V7 BSD 2.8 and
  56. XBSD 2.9, a pyramid 98X and on a unisoft 68000 (V7) system. With
  57. Xappropriate convertion of the terminal handling routines (about 20 lines
  58. Xof code) it should run on System V systems as well.
  59. X
  60. XThe system dependent code has been extracted and placed in relevent
  61. Xsubdirectories. Follow one of the current systems for conversion guidance.
  62. XThe only nasty is that it assumes (in print()) that ints and structure
  63. Xpointers are the same size. This can be fixed but I don't want to do it.
  64. X(It also assumes that all pointer types are the same size which I
  65. Xwouldn't like to have to fix)
  66. X
  67. XTo compile the system use the "gen" shell script which will do all the
  68. Xwork.
  69. X
  70. XYou may want to sort out the terminal handling/editing routines as
  71. Xwell.
  72. X
  73. XHave fun.
  74. X
  75. XPhil Cockcroft  Fall, 86
  76. X------------------------
  77. End of README
  78. chmod u=rw-,g=r,o=r README
  79. echo x - assist.c 1>&2
  80. sed 's/^X//' > assist.c << 'End of assist.c'
  81. X/*
  82. X * BASIC by Phil Cockcroft
  83. X */
  84. X#include "bas.h"
  85. X
  86. X/* this file contains all the routines that were originally done in assembler
  87. X * these routines only require a floating point emulator to work.
  88. X * To speed things up some routines could be put into assembler and some
  89. X * could be made into macros. the relevent routines are labeled as such
  90. X */
  91. X
  92. X#ifndef VAX_ASSEM       /* if done in assembler don't bring it in */
  93. X/* AS */
  94. X
  95. X/* get a single character from the line pointed to by getch() */
  96. X
  97. Xgetch()
  98. X{
  99. X    register char   *p;
  100. X
  101. X    p = point;
  102. X    while(*p++ == ' ');
  103. X    point = p;
  104. X    return(*--p & 0377);
  105. X}
  106. X
  107. X/* AS  #define  ELSE 0351 */
  108. X
  109. Xcheck()         /* check to see no garbage at end of command */
  110. X{
  111. X    register char   *p;
  112. X    register char   c;
  113. X
  114. X    p = point;
  115. X    while(*p++ == ' ');
  116. X    if(! (c = *--p) || c == ':' || (c == (char)ELSE && elsecount)){
  117. X        point = p;
  118. X        return;
  119. X    }
  120. X    error(SYNTAX);          /* not a terminator - error */
  121. X}
  122. X#endif
  123. X
  124. X#ifndef SOFTFP
  125. Xfpcrash()
  126. X{
  127. X    error(34);      /* arithmetic overflow */
  128. X}
  129. X#endif
  130. X
  131. Xint     (*fpfunc)();
  132. X
  133. Xstartfp()
  134. X{
  135. X#ifndef SOFTFP
  136. X    fpfunc = fpcrash;       /* will call error(34) on overflow */
  137. X#else
  138. X    fpfunc = 0;
  139. X#endif
  140. X}
  141. X
  142. X/* AS */
  143. X
  144. X/* compare two values. return 0 if equal -1 if first less than second
  145. X * or 1 for vice versa.
  146. X */
  147. X
  148. Xcmp(p,q)
  149. Xregister value  *p,*q;
  150. X{
  151. X    if(vartype){
  152. X        if(p->i == q->i)
  153. X            return(0);
  154. X        else if(p->i < q->i)
  155. X            return(-1);
  156. X        return(1);
  157. X    }
  158. X    if(p->f == q->f)
  159. X        return(0);
  160. X    else if(p->f< q->f )
  161. X        return(-1);
  162. X    return(1);
  163. X}
  164. X
  165. X/* the arithmetic operation jump table */
  166. X
  167. X
  168. X/* all the routines below should be put into AS */
  169. X
  170. Xint     fandor(), andor(), comop(), fads(), ads(),
  171. X    fmdm(), mdm(), fexp(), ex();
  172. X
  173. Xint     (*mbin[])() = {
  174. X    0,0,
  175. X    fandor,
  176. X    andor,
  177. X    comop,
  178. X    comop,
  179. X    fads,
  180. X    ads,
  181. X    fmdm,
  182. X    mdm,
  183. X    fexp,
  184. X    ex,
  185. X    };
  186. X
  187. Xtypedef value   *valp;
  188. X
  189. Xex(p,q,c)               /* integer exponentiation */
  190. Xvalp    p,q;
  191. X{
  192. X    cvt(p);
  193. X    cvt(q);
  194. X    vartype = 0;
  195. X    fexp(p,q,c);
  196. X}
  197. X
  198. Xfmdm(p,q,c)             /* floating * / mod */
  199. Xvalp    p,q;
  200. X{
  201. X    double  floor(),x;
  202. X    if(c == '*'){
  203. X        fmul(p,q);
  204. X        return;
  205. X    }
  206. X    if(q->f == 0)
  207. X        error(25);
  208. X    if(c=='/')
  209. X        fdiv(p,q);
  210. X    else  {         /* floating mod - yeuch */
  211. X        if( (x = p->f/q->f) < 0)
  212. X            q->f = p->f + floor(-x) * q->f;
  213. X        else
  214. X            q->f = p->f - floor(x) * q->f;
  215. X    }
  216. X}
  217. X
  218. Xmdm(p,q,c)              /* integer * / mod */
  219. Xvalp    p,q;
  220. X{
  221. X    register long    l;
  222. X    register short  ll;
  223. X
  224. X    l = p->i;
  225. X    if(c=='*'){
  226. X        l *= q->i;
  227. X#ifdef  VAX_ASSEM
  228. X        ll = l;
  229. X        { asm("bvc mdmov"); }
  230. X            q->f = l;
  231. X            vartype = 0;
  232. X            { asm("ret"); }         /* could be 'return' */
  233. X        { asm("mdmov: "); }
  234. X        q->i = ll;
  235. X#else
  236. X        if(l > 32767 || l < -32768){    /* overflow */
  237. X            q->f = l;
  238. X            vartype = 0;
  239. X        }
  240. X        else q->i = l;
  241. X#endif
  242. X        return;
  243. X    }
  244. X    if(!q->i)                       /* zero divisor error */
  245. X        error(25);
  246. X    ll = p->i % q->i;
  247. X    if(c == '/'){
  248. X        if(ll){
  249. X            q->f = (double)l / q->i;
  250. X            vartype = 0;
  251. X        }
  252. X        else
  253. X            q->i = p->i / q->i;
  254. X    }
  255. X    else
  256. X        q->i = ll;
  257. X}
  258. X
  259. Xfads(p,q,c)             /* floating + - */
  260. Xvalp    p,q;
  261. X{
  262. X    if(c=='+')
  263. X        fadd(p,q);
  264. X    else
  265. X        fsub(p,q);
  266. X}
  267. X
  268. Xads(p,q,c)              /* integer + - */
  269. Xvalp    p,q;
  270. X{
  271. X    register long   l;
  272. X#ifdef  VAX_ASSEM
  273. X    register short  ll;
  274. X#endif
  275. X
  276. X    l = p->i;
  277. X    if(c == '+')
  278. X        l += q->i;
  279. X    else
  280. X        l -= q->i;
  281. X#ifdef  VAX_ASSEM
  282. X        ll = l;
  283. X        { asm("bvc adsov"); }
  284. X            q->f = l;
  285. X            vartype = 0;
  286. X            { asm("ret"); }         /* could be 'return' */
  287. X        { asm("adsov: "); }
  288. X        q->i = ll;
  289. X#else
  290. X    if(l > 32767 || l < -32768){    /* overflow */
  291. X        q->f = l;
  292. X        vartype = 0;
  293. X    }
  294. X    else
  295. X        q->i = l;
  296. X#endif
  297. X}
  298. X
  299. Xcomop(p,q,c)                    /* comparison operations */
  300. Xvalp    p,q;
  301. X{
  302. X    compare(c,cmp(p,q));
  303. X}
  304. X
  305. Xfandor(p,q,c)                   /* floating logical AND/OR/XOR */
  306. Xregister valp    p,q;
  307. X{
  308. X    vartype = 01;
  309. X#ifdef  PORTABLE
  310. X    p->i = ((p->f != 0.0) ? -1 : 0);
  311. X    q->i = ((q->f != 0.0) ? -1 : 0);
  312. X#else
  313. X    p->i = (p->i ? -1 : 0);
  314. X    q->i = (q->i ? -1 : 0);
  315. X#endif
  316. X    andor(p,q,c);
  317. X}
  318. X
  319. Xandor(p,q,c)                    /* integer logical */
  320. Xvalp    p,q;
  321. X{
  322. X    register i,j;
  323. X
  324. X    i = p->i;
  325. X    j = q->i;
  326. X    if(c == ANDD)           /* and */
  327. X        i &= j;
  328. X    else if(c == ORR)       /* or */
  329. X        i |= j;
  330. X    else
  331. X        i ^= j;         /* xor */
  332. X    q->i = i;
  333. X}
  334. X
  335. X/* down to about here */
  336. X
  337. X/* MACRO */
  338. X
  339. Xputin(p,var)            /* convert + put the value in res into p */
  340. Xmemp    p;
  341. Xchar    var;
  342. X{
  343. X    if(vartype != var){
  344. X        if(var){
  345. X            if(conv(&res))
  346. X                error(35);
  347. X        }
  348. X        else
  349. X            cvt(&res);
  350. X    }
  351. X    if(var)
  352. X        ((value *)p)->i = res.i;
  353. X    else
  354. X        ((value *)p)->f = res.f;
  355. X}
  356. X
  357. X/* MACRO */
  358. X
  359. Xnegate()                /* negate the value in res */
  360. X{
  361. X    if(vartype){
  362. X        if(res.i == -32768){    /* special case */
  363. X            res.f = 32768;
  364. X            vartype = 0;
  365. X        }
  366. X        else
  367. X            res.i = -res.i;
  368. X    }
  369. X    else
  370. X        res.f = -res.f;
  371. X}
  372. X
  373. X/* MACRO */
  374. X
  375. Xnotit()                 /* logical negation */
  376. X{
  377. X    if(vartype){
  378. X        res.i = ~res.i;
  379. X        return;
  380. X    }
  381. X    vartype = 01;
  382. X#ifdef  PORTABLE
  383. X    if(res.f)
  384. X        res.i = 0;
  385. X    else
  386. X        res.i = -1;
  387. X#else
  388. X    if(res.i)
  389. X        res.i = 0;
  390. X    else
  391. X        res.i = -1;
  392. X#endif
  393. X}
  394. X
  395. Xfexp(p,q,c)                     /* floating exponentiation */
  396. Xvalp    p,q;
  397. X{
  398. X    double  x,log(),exp();
  399. X
  400. X    if(p->f < 0)
  401. X        error(41);
  402. X    else if(q->f == 0.0)
  403. X        q->f = 1.0;
  404. X    else if(p->f == 0.0)            /* could use pow - but not on v6 */
  405. X        q->f = 0.0;
  406. X    else {
  407. X        if( (x = log(p->f) * q->f) > 88.02969) /* should be bigger */
  408. X            error(40);
  409. X        q->f = exp(x);
  410. X    }
  411. X}
  412. End of assist.c
  413. chmod u=rw-,g=r,o=r assist.c
  414. echo x - bas.h 1>&2
  415. sed 's/^X//' > bas.h << 'End of bas.h'
  416. X/*
  417. X * BASIC by Phil Cockcroft
  418. X */
  419. X/*
  420. X *      This file contains all the variables and definitions needed by
  421. X *    all the C parts of the interpreter.
  422. X */
  423. X
  424. X/*
  425. X * include the correct include file for the current machine
  426. X */
  427. X
  428. X#ifdef  vax
  429. X#include "vax/conf.h"
  430. X#endif
  431. X#ifdef  pdp11
  432. X#include "pdp11/conf.h"
  433. X#endif
  434. X#ifdef  m68000
  435. X#include "m68000/conf.h"
  436. X#endif
  437. X#ifdef  pyramid
  438. X#include "pyramid/conf.h"
  439. X#endif
  440. X
  441. X#define MASK            0377
  442. X#define SPECIAL         0200            /* top bit set */
  443. X#define SYNTAX          1               /* error code */
  444. X#define MAXLIN          255             /* maximum length of input line */
  445. X#define BUSERR          10              /* bus error */
  446. X#define SEGERR          11              /* segmentation violation */
  447. X#define DEFAULTSTRING   512             /* default size of string space */
  448. X#define VARREQD         2               /* error code */
  449. X#define OUTOFSTRINGSPACE 3              /* ditto */
  450. X#define NORMAL          0               /* normal return from a command */
  451. X#define GTO             1               /* ignore rest of line return */
  452. X#define normret return(NORMAL)
  453. X#define MAXERR          51              /* maximum value of error code */
  454. X#define BADDATA         26              /* error message values */
  455. X#define OUTOFDATA       27
  456. X#define FUNCT           33
  457. X#define FLOATOVER       34
  458. X#define INTOVER         35
  459. X#define REDEFFN         45
  460. X#define UNDEFFN         46
  461. X#define CANTCONT        47
  462. X
  463. X#ifdef  LNAMES                          /* if you want long names... */
  464. X
  465. X#define MAXNAME         16              /* maximum size of a name -1 */
  466. X#define HSHTABSIZ       37              /* size of initial hash table */
  467. X                    /* very rule of thumb. */
  468. X#endif
  469. X
  470. X/*
  471. X *      values of constants from the symbol table
  472. X */
  473. X
  474. X#define MAXFUNC         0350            /* maximum allowed function code */
  475. X#define RND             0343            /* rnd function code */
  476. X#define FN              0344
  477. X#define MINFUNC         0311
  478. X#define MAXSTRING       0307
  479. X#define DATE            0310
  480. X#define MAXCOMMAND      0272            /* maximum allowed command code */
  481. X#define MINSTRING       0271            /* the rest are pretty obvious */
  482. X#define DATA            0236
  483. X#define QUOTE           0233
  484. X#define ERROR           0231
  485. X#define GOSUB           0226
  486. X#define FOR             0224
  487. X#define IF              0221
  488. X#define INPUT           0212
  489. X#define RUNN            0201
  490. X#define REM             0203
  491. X#define GOTO            0202
  492. X#define WHILE           0257
  493. X#define WEND            0260
  494. X#define REPEAT          0255
  495. X#define UNTIL           0256
  496. X#define ELSE            0351
  497. X#define THEN            0352
  498. X#define ON              0230
  499. X#define RESUME          0220
  500. X#define RESTORE         0240
  501. X#define TABB            0353            /* tab command */
  502. X#define STEP            0354
  503. X#define TO              0355
  504. X#define AS              0365
  505. X#define OUTPUT          0366
  506. X#define APPEND          0367
  507. X#define TERMINAL        0371
  508. X
  509. X/*      logical operators */
  510. X
  511. X#define MODD            0361
  512. X#define ANDD            0356
  513. X#define ORR             0357
  514. X#define XORR            0360
  515. X#define NOTT            0370
  516. X
  517. X/*      comparison operators */
  518. X
  519. X#define EQL             '='
  520. X#define LTEQ            0362
  521. X#define NEQE            0363
  522. X#define LTTH            '<'
  523. X#define GTEQ            0364
  524. X#define GRTH            '>'
  525. X
  526. X/*      values used for file maintainance */
  527. X
  528. X#define _READ           01
  529. X#define _WRITE          02
  530. X#define _EOF            04
  531. X#define _TERMINAL       010
  532. X
  533. X/*
  534. X   N.B. The value of this (_BLOCKED) controls wether the blockmode file stuff
  535. X    is included. ( comment this constant out if don't want it).
  536. X*/
  537. X#define _BLOCKED        020
  538. X
  539. X#define MAXFILES        9
  540. X
  541. X#define ESCAPE        '\033'
  542. X
  543. X/*      definitions of some simple functions */
  544. X/*      isletter()      - true if character is a letter */
  545. X/*      isnumber()      - true if character is a number */
  546. X/*      istermin()      - true if character is a terminator */
  547. X
  548. X#define isletter(c)  ((c)>='a' && (c)<='z')
  549. X#define isnumber(c)  ((c)>='0' && (c)<='9')
  550. X#define istermin(c)  (!(c)|| (c)==':' ||((char)(c)==(char)ELSE && elsecount))
  551. X
  552. X/*      define the offset to the next line */
  553. X
  554. X#define lenv(p)      ((p)->llen)
  555. X
  556. Xtypedef struct  olin    *lpoint;        /* typedef for pointer to a line */
  557. Xtypedef struct  deffn   *deffnp;        /* pointer to a function definition */
  558. Xtypedef struct  filebuf *filebufp;      /* pointer to a filebuffer */
  559. Xtypedef struct  forst   *forstp;        /* pointer to a for block */
  560. Xtypedef struct  strarr  *strarrp;       /* pointer to an array header */
  561. Xtypedef struct  vardata *vardp;         /* pointer to a variable */
  562. Xtypedef struct  stdata  *stdatap;       /* pointer to a string header */
  563. Xtypedef char    *memp;                  /* a memory pointer */
  564. X
  565. X/*      typedef fo the standard dual type of variable */
  566. X
  567. Xtypedef union {
  568. X        short   i;
  569. X        double  f;
  570. X       } value;
  571. X
  572. X/*      declarations to stop the C compiler complaining */
  573. X
  574. Xfilebufp getf();
  575. Xlpoint  getline();
  576. Xmemp    xpand(),getname();
  577. Xchar    *printlin(),*strcpy(),*grow(),*getenv();
  578. X
  579. Xint     rnd(),ffn(),pii(),erlin(),erval(),tim();
  580. Xint     sgn(),len(),abs(),val(),ascval(),instr(),eofl(),fposn(),sqrtf(),
  581. X    logf(),expf(),evalu(),intf(),peekf(),sinf(),cosf(),atanf(),
  582. X    mkint(),mkdouble(), ssystem();
  583. Xint     midst(),rightst(),leftst(),strng(),estrng(),chrstr(),nstrng(),
  584. X    space(),getstf(),mkistr(),mkdstr();
  585. Xint     endd(),runn(),gotos(),rem(),lets(),list(),
  586. X    print(),stop(),delete(),editl(),input(),clearl(),
  587. X    save(),old(),neww(),shell(),resume(),iff(),
  588. X    random(),dimensio(),forr(),next(),gosub(),retn(),
  589. X    onn(),doerror(),print(),rem(),dauto(),
  590. X    readd(),dodata(),cls(),restore(),base(),fopen(),
  591. X    fclosef(),merge(),quit(),chain(),deffunc(),cont(),lhmidst(),
  592. X    linput(),poke(),rept(),untilf(),whilef(),wendf(),fseek(),renumb(),
  593. X    dump(),loadd();
  594. X
  595. X/*      all structures must have an exact multiple of the size of an int
  596. X *    to the start of the next structure
  597. X */
  598. X
  599. Xstruct  stdata  {               /* data for the string pointer */
  600. X    unsigned snam;          /* getname() will return the address */
  601. X    char    *stpt;          /* of this structure for a string access */
  602. X    };
  603. X
  604. Xstruct  vardata {               /* storage of a standard non-indexed */
  605. X    unsigned nam;           /* variable */
  606. X    value   dt;
  607. X    };
  608. X
  609. Xtypedef unsigned xlinnumb;      /* the type of linnumbers */
  610. X
  611. Xstruct olin{                    /* structure for a line */
  612. X    unsigned linnumb;
  613. X    unsigned llen;
  614. X    char     lin[1];
  615. X    };
  616. X
  617. Xstruct  strarr {                /* structure for an array */
  618. X    unsigned snm;           /* name */
  619. X    int     hash;           /* index to the next array or the start */
  620. X    short   dimens;         /* of the special numbers */
  621. X    short   dim[3];         /* the dimensions */
  622. X    };
  623. X
  624. X
  625. Xstruct  forst {                 /* for / gosub stack */
  626. X    char    *fnnm;          /* pointer to variable - relative to earray */
  627. X    char    fr,elses;       /* type of structure , elsecount on return */
  628. X    value   final;          /* the start and end values */
  629. X    value   step;
  630. X    lpoint  stolin;         /* pointer to return start of line */
  631. X    char    *pt;            /* return value for point */
  632. X    };
  633. X
  634. X#ifdef  LNAMES
  635. X
  636. Xstruct  entry   {               /* the structure for a long name storage */
  637. X    struct  entry   *link;
  638. X    int     ln_hash;        /* hash value of entry */
  639. X    char    _name[MAXNAME];
  640. X    };
  641. X
  642. X#endif
  643. X
  644. X#ifdef  V7
  645. X
  646. X#include        <setjmp.h>
  647. X#include        <signal.h>
  648. X#include        <sys/types.h>
  649. X#include        <sys/stat.h>
  650. X
  651. X#define setexit()       setjmp(rcall)
  652. X#define reset()         longjmp(rcall,0)
  653. X
  654. X#else
  655. X
  656. Xstruct  stat    {
  657. X    short   st_dev;
  658. X    short   st_ino;
  659. X    short   st_mode;
  660. X    int     _stat[15];
  661. X    };
  662. X
  663. X#define _exit(x)        exit(x)
  664. X
  665. Xint     (*signal())();
  666. X#define SIGINT  2
  667. X#define SIGQUIT 3
  668. X#define SIGFPE  8
  669. X#define SIG_IGN ((int(*)())1)
  670. X#define SIG_DFL ((int(*)())0)
  671. X#define NSIG    16
  672. X
  673. X#endif
  674. X
  675. X#ifndef pdp11           /* don't need it on a VAX system */
  676. X#define checksp()       /* nothing */
  677. X#endif
  678. X
  679. Xstruct  filebuf {               /* the file buffer structure */
  680. X    short   filedes;        /* system file descriptor */
  681. X    short   userfiledes;    /* user name */
  682. X    int     posn;           /* cursor / read positon */
  683. X#ifdef  _BLOCKED
  684. X    short   blocksiz;       /* if want block mode files */
  685. X#endif
  686. X    short   inodnumber;     /* to stop people reading and writing */
  687. X    short   device;         /* to the same file at the same time */
  688. X    short   use;            /* flags */
  689. X    short   nleft;          /* number of characters in buffer */
  690. X    char    buf[BLOCKSIZ];  /* the buffer itself */
  691. X    };
  692. X
  693. Xstruct tabl {                   /* structure for symbol table */
  694. X    char    *string;
  695. X    int     chval;
  696. X    };
  697. X
  698. Xstruct  deffn  {                /* structure for a user definable function */
  699. X    int     dnm;
  700. X    int     offs;
  701. X    char    narg;
  702. X    char    vtys;
  703. X    short   vargs[3];
  704. X    char    exp[1];
  705. X    };
  706. X
  707. X#ifndef SOFTFP
  708. X
  709. X#define fadd(p,q)       ((q)->f += (p)->f)
  710. X#define fsub(p,q)       ((q)->f = (p)->f - (q)->f)
  711. X#define fmul(p,q)       ((q)->f *= (p)->f)
  712. X#define fdiv(p,q)       ((q)->f = (p)->f / (q)->f)
  713. X
  714. X#define conv(p) \
  715. X    ( ((p)->f > MAXint || (p)->f < MINint) ? 1 : ( ((p)->i = (p)->f), 0) )
  716. X
  717. X#define cvt(p)  (p)->f = (p)->i
  718. X
  719. X#endif
  720. X
  721. X/*
  722. X * On pdp11's and VAXen the loader is clever about global bss symbols
  723. X * On 68000's this is not true so we have to define the memory pointers
  724. X * to be members of an array.
  725. X */
  726. X#ifdef  MPORTABLE
  727. X#define estring _space_[0]
  728. X#ifdef  LNAMES
  729. X#define enames  _space_[1]
  730. X#define edefns  _space_[2]
  731. X#define estarr  _space_[3]
  732. X#define earray  _space_[4]
  733. X#define vend    _space_[5]
  734. X#define bstk    _space_[6]
  735. X#define vvend   _space_[7]
  736. X#else
  737. X#define edefns  _space_[1]
  738. X#define estarr  _space_[2]
  739. X#define earray  _space_[3]
  740. X#define vend    _space_[4]
  741. X#define bstk    _space_[5]
  742. X#define vvend   _space_[6]
  743. X#endif
  744. X
  745. X#endif
  746. X
  747. X
  748. X/*
  749. X *      PART1 is declared only once and so allocates storage for the
  750. X *    variables only once , otherwise the definiton for the variables
  751. X *    ( in all source files except bas1.c ). is declared as external.
  752. X */
  753. X
  754. X#ifdef  PART1
  755. X
  756. Xint     baseval=1;              /* value of the initial base for arrays */
  757. Xchar    nl[]="\n";              /* a new_line character */
  758. Xchar    line[MAXLIN+2];         /* the input line */
  759. Xchar    nline[MAXLIN];         /* the array used to store the compiled line */
  760. Xunsigned linenumber;            /* linenumber form compile */
  761. X
  762. X/*  pointers to the various sections of the memory map */
  763. X
  764. Xmemp    filestart;      /* end of bss , start of file buffers */
  765. Xmemp    fendcore;       /* end of buffers , start of text */
  766. Xmemp    ecore;          /* end of text , start of string space */
  767. Xmemp    eostring;       /* end of full strings */
  768. Xmemp    estdt;          /* start of string header blocks */
  769. X
  770. X/* all these pointers below must be defined in this order so that xpand
  771. X * will be able to increment them all */
  772. X
  773. X#ifndef MPORTABLE
  774. Xmemp    estring;        /* end of strings , start of func defs */
  775. X#ifdef  LNAMES
  776. Xmemp    enames;         /* end of symbol table. start of def fncs */
  777. X#endif
  778. Xmemp    edefns;         /* end of def fncs , start of arrays */
  779. Xmemp    estarr;         /* end of string array structures */
  780. Xmemp    earray;         /* end of arrays , start of simple variables */
  781. Xmemp    vend;           /* end of simple variables , start of gosub stack */
  782. Xmemp    bstk;
  783. Xmemp    vvend;          /* end of stack , top of memory */
  784. X#else
  785. Xmemp    _space_[8];     /* for use in portable systems */
  786. X#endif
  787. X
  788. X/* up to this point */
  789. X
  790. Xint     cursor;         /* position of cursor on line */
  791. Xunsigned shash;         /* starting value for string arrays */
  792. Xint     mcore();        /* trap functions- keep compiler happy */
  793. Xint     seger();
  794. Xint     trap();
  795. Xlpoint  stocurlin;      /* start of current line */
  796. Xunsigned curline;       /* current line number */
  797. Xint     readfile;       /* input file , file descriptor */
  798. Xchar    *point;         /* pointer to current location */
  799. Xchar    *savepoint;     /* value of point at start of current command */
  800. Xchar    elsecount;      /* flag for enabling ELSEs as terminators */
  801. Xchar    vartype;        /* current type of variable */
  802. Xchar    runmode;        /* run or immeadiate mode */
  803. Xchar    ertrap;         /* are about to call the error trapping routine */
  804. Xchar    intrap;         /* we are in the error trapping routine */
  805. Xchar    trapped;        /* cntrl-c trap has occured */
  806. Xchar    inserted;       /* the line table has been changed, clear variables */
  807. Xchar    eelsecount;     /* variables to save the current state after an */
  808. Xlpoint  estocurlin;     /* error */
  809. Xunsigned elinnumb;      /* ditto */
  810. Xchar    *epoint;        /* ditto */
  811. Xint     ecode;          /* error code */
  812. Xlpoint  errortrap;      /* error trap pointer */
  813. Xlpoint  saveertrap;     /* error trap save location - during trap  */
  814. Xlpoint  datastolin;     /* pointer to start of current data line */
  815. Xchar    *datapoint;     /* pointer into current data line */
  816. Xint     evallock;       /* lock to stop recursive eval function */
  817. Xunsigned autostart=10;  /* values for auto command */
  818. Xunsigned autoincr=10;
  819. Xint     ter_width;      /* set from the terms system call */
  820. X
  821. Xlpoint  constolin;      /* values for 'cont' */
  822. Xunsigned concurlin;
  823. Xlpoint  conerp;
  824. Xchar    *conpoint;
  825. Xchar    contelse;
  826. Xchar    contpos;
  827. Xchar    cancont;
  828. Xchar    noedit;         /* set if noediting is to be done */
  829. X
  830. Xint     pipes[2];       /* pipe structure for chain */
  831. X
  832. Xlong    overfl;         /* value of overflowed integers, converting to real */
  833. X
  834. Xvalue   res;            /* global variable for maths function */
  835. X
  836. Xdouble  pivalue= 3.14159265358979323846;        /* value of pi */
  837. X#ifndef SOFTFP
  838. Xdouble  MAXint= 32767;                          /* for cvt */
  839. Xdouble  MINint= -32768;
  840. X#endif
  841. X
  842. X#ifdef  V7
  843. Xjmp_buf rcall;
  844. X#endif
  845. X#ifdef  BSD42
  846. Xjmp_buf ecall;                  /* for use of cntrl-c in edit */
  847. Xchar    ecalling;
  848. X#endif
  849. X                /* one edit mode , one for normal mode */
  850. Xint     nm;                     /* name of variable being accessed */
  851. X
  852. X#ifdef  LNAMES
  853. Xchar    nam[MAXNAME];                   /* local array for long names */
  854. Xstruct  entry   *hshtab[HSHTABSIZ];     /* hash table pointers */
  855. Xint     varshash[HSHTABSIZ];            /* hashing for variables */
  856. Xint     chained;                /* force full search only after a chain() */
  857. X#endif
  858. X
  859. Xchar    gblock[256];            /* global place for string functions */
  860. Xint     gcursiz;                /* size of string in gblock[] */
  861. X
  862. X/*
  863. X *      definition of the command , function and string function 'jump'
  864. X *    tables.
  865. X */
  866. X
  867. X/*      maths functions that do not want an argument */
  868. X
  869. Xint     (*functs[])()= {
  870. X    rnd,ffn, pii, erlin, erval, tim,
  871. X    };
  872. X
  873. X/*      other maths functions */
  874. X
  875. Xint     (*functb[])()={
  876. X    sgn, len, abs, val, ascval, instr, eofl, fposn, sqrtf, logf, expf,
  877. X    evalu,intf,peekf,sinf,cosf,atanf,mkint,mkdouble, ssystem,
  878. X    };
  879. X
  880. X/*      string function , N.B. date$ is not here. */
  881. X
  882. Xint     (*strngcommand[])()= {
  883. X    midst, rightst, leftst, strng, estrng, chrstr, nstrng, space, getstf,
  884. X    mkistr,mkdstr,
  885. X    };
  886. X
  887. X/*      commands */
  888. X
  889. Xint     (*commandf[])()= {
  890. X    endd,runn,gotos,rem,list,lets,print,stop,delete,editl,input,clearl,
  891. X    save,old,neww,shell,resume,iff,random,dimensio,forr,next,gosub,retn,
  892. X    onn,doerror,print,rem,dauto,readd,dodata,cls,restore,base,fopen,
  893. X    fclosef,merge,quit,quit,quit,chain,deffunc,cont,poke,linput,rept,
  894. X    untilf,whilef,wendf,fseek,renumb,loadd,dump,0,0,0,0,lhmidst,
  895. X    };
  896. X
  897. X/*      table of error messages */
  898. X
  899. Xchar    *ermesg[]= {
  900. X    "syntax error",
  901. X    "variable required",
  902. X    "out of string space",
  903. X    "assignment '=' required",
  904. X    "line number required",
  905. X    "undefined line number",
  906. X    "line number overflow",
  907. X    "illegal command",
  908. X    "string overflow",
  909. X    "illegal string size",
  910. X    "illegal function",
  911. X    "illegal core size",
  912. X    "illegal edit",
  913. X    "cannot creat file",
  914. X    "cannot open file",
  915. X    "dimension error",
  916. X    "subscript error",
  917. X    "next without for",
  918. X    "undefined array",
  919. X    "redimension error",
  920. X    "gosub / return error",
  921. X    "illegal error code",
  922. X    "bad load",
  923. X    "out of core",
  924. X    "zero divisor error",
  925. X    "bad data",
  926. X    "out of data",
  927. X    "bad base",
  928. X    "bad file descriptor",
  929. X    "unexpected eof",
  930. X    "out of files",
  931. X    "line length overflow",
  932. X    "argument error",
  933. X    "floating point overflow",
  934. X    "integer overflow",
  935. X    "bad number",
  936. X    "negative square root",
  937. X    "negative or zero log",
  938. X    "overflow in exp",
  939. X    "overflow in power",
  940. X    "negative power",
  941. X    "no space for chaining",
  942. X    "mutually recursive eval",
  943. X    "expression too complex",
  944. X    "illegal redefinition",
  945. X    "undefined user function",
  946. X    "can't continue",
  947. X    "until without repeat",
  948. X    "wend without while",
  949. X    "no wend statement found",
  950. X    "illegal loop nesting",
  951. X    };
  952. X
  953. X/*      tokenising table */
  954. X
  955. Xstruct  tabl    table[]={
  956. X    "end",0200,             /* commands 0200 - 0300 */
  957. X    "run",0201,
  958. X    "goto",0202,
  959. X    "rem",0203,
  960. X    "list",0204,
  961. X    "let",0205,
  962. X    "print",0206,
  963. X    "stop",0207,
  964. X    "delete",0210,
  965. X    "edit",0211,
  966. X    "input",0212,
  967. X    "clear",0213,
  968. X    "save",0214,
  969. X    "old",0215,
  970. X    "new",0216,
  971. X    "shell",0217,
  972. X    "resume",0220,
  973. X    "if",0221,
  974. X    "random",0222,
  975. X    "dim",0223,
  976. X    "for",0224,
  977. X    "next",0225,
  978. X    "gosub",0226,
  979. X    "return",0227,
  980. X    "on",0230,
  981. X    "error",0231,
  982. X    "?",0232,
  983. X    "'",0233,
  984. X    "auto",0234,
  985. X    "read",0235,
  986. X    "data",0236,
  987. X    "cls",0237,
  988. X    "restore",0240,
  989. X    "base",0241,
  990. X    "open",0242,
  991. X    "close",0243,
  992. X    "merge",0244,
  993. X    "quit",0245,
  994. X    "bye",0246,
  995. X    "exit",0247,
  996. X    "chain",0250,
  997. X    "def",0251,
  998. X    "cont",0252,
  999. X    "poke",0253,
  1000. X    "linput",0254,
  1001. X    "repeat",0255,
  1002. X    "until",0256,
  1003. X    "while",0257,
  1004. X    "wend",0260,
  1005. X    "seek",0261,
  1006. X#ifdef  RENUMB
  1007. X    "renumber",0262,
  1008. X#endif
  1009. X    "load",0263,
  1010. X    "dump",0264,
  1011. X    "mid$",0271,            /* string functions 0271 - 0310 */
  1012. X    "right$",0272,
  1013. X    "left$",0273,
  1014. X    "string$",0274,
  1015. X    "ermsg$",0275,
  1016. X    "chr$",0276,
  1017. X    "str$",0277,
  1018. X    "space$",0300,
  1019. X    "get$",0301,
  1020. X#ifdef  _BLOCKED
  1021. X    "mkis$",0302,
  1022. X    "mkds$",0303,
  1023. X#endif
  1024. X    "date$",0310,           /* date must be last string funct */
  1025. X    "sgn",0311,             /* maths functions 0311 - 0350 */
  1026. X    "len",0312,
  1027. X    "abs",0313,
  1028. X    "val",0314,
  1029. X    "asc",0315,
  1030. X    "instr",0316,
  1031. X    "eof",0317,
  1032. X    "posn",0320,
  1033. X    "sqrt",0321,
  1034. X    "log",0322,
  1035. X    "exp",0323,
  1036. X    "eval",0324,
  1037. X    "int",0325,
  1038. X    "peek",0326,
  1039. X    "sin",0327,
  1040. X    "cos",0330,
  1041. X    "atan",0331,
  1042. X#ifdef  _BLOCKED
  1043. X    "mksi",0332,
  1044. X    "mksd",0333,
  1045. X#endif
  1046. X    "system", 0334,
  1047. X    "rnd",0343,
  1048. X    "fn",0344,
  1049. X    "pi",0345,
  1050. X    "erl",0346,
  1051. X    "err",0347,
  1052. X    "tim",0350,
  1053. X    "else",0351,            /* seperators and others 0351 - 0377 */
  1054. X    "then",0352,
  1055. X    "tab",0353,
  1056. X    "step",0354,
  1057. X    "to",0355,
  1058. X    "and",0356,
  1059. X    "or",0357,
  1060. X    "xor",0360,
  1061. X    "mod",0361,
  1062. X    "<=",0362,
  1063. X    "<>",0363,
  1064. X    ">=",0364,
  1065. X    "as",0365,
  1066. X    "output",0366,
  1067. X    "append",0367,
  1068. X    "not",0370,
  1069. X    "terminal",0371,
  1070. X    0,0
  1071. X    };
  1072. X
  1073. X#else
  1074. X
  1075. X/*   definition of variables for other source files */
  1076. X
  1077. Xextern  int     baseval;
  1078. Xextern  char    nl[];
  1079. Xextern  char    line[];
  1080. Xextern  char    nline[];
  1081. Xextern  unsigned linenumber;
  1082. Xextern  memp    fendcore;
  1083. X#ifndef MPORTABLE
  1084. Xextern  memp    estring,edefns,estarr,earray,vend,bstk,vvend;
  1085. X#else
  1086. Xextern  memp    _space_[];
  1087. X#endif
  1088. Xextern  memp    filestart;
  1089. Xextern  memp    ecore,eostring,estdt;
  1090. Xextern  int     cursor;
  1091. Xextern  unsigned shash;
  1092. Xextern  int     mcore(),seger(),trap();
  1093. Xextern  lpoint  stocurlin;
  1094. Xextern  unsigned curline;
  1095. Xextern  int     readfile;
  1096. Xextern  char    *point;
  1097. Xextern  char    *savepoint;
  1098. Xextern  char    elsecount;
  1099. Xextern  char    vartype;
  1100. Xextern  char    runmode;
  1101. Xextern  char    ertrap;
  1102. Xextern  char    intrap;
  1103. Xextern  char    trapped;
  1104. Xextern  char    inserted;
  1105. Xextern  char    eelsecount;
  1106. Xextern  lpoint  estocurlin;
  1107. Xextern  unsigned elinnumb;
  1108. Xextern  char    *epoint;
  1109. Xextern  int     ecode;
  1110. Xextern  lpoint  errortrap;
  1111. Xextern  lpoint  saveertrap;
  1112. Xextern  lpoint  datastolin;
  1113. Xextern  char    *datapoint;
  1114. Xextern  int     evallock;
  1115. Xextern  unsigned autostart;
  1116. Xextern  unsigned autoincr;
  1117. Xextern  int     ter_width;
  1118. Xextern  lpoint  constolin;
  1119. Xextern  unsigned concurlin;
  1120. Xextern  lpoint  conerp;
  1121. Xextern  char    *conpoint;
  1122. Xextern  char    contelse;
  1123. Xextern  char    contpos;
  1124. Xextern  char    cancont;
  1125. Xextern  char    noedit;
  1126. X
  1127. Xextern  int     pipes[];
  1128. X
  1129. Xextern  long    overfl;
  1130. Xextern  value   res;
  1131. X
  1132. Xextern  double  pivalue;
  1133. Xextern  double  MAXint,MINint;
  1134. X#ifdef  V7
  1135. Xextern  jmp_buf rcall;
  1136. X#endif
  1137. X
  1138. X#ifdef  BSD42
  1139. Xextern  jmp_buf ecall;
  1140. Xextern  char    ecalling;
  1141. X#endif
  1142. X
  1143. Xextern  int     nm;
  1144. X
  1145. X#ifdef  LNAMES
  1146. Xextern  struct  entry   *hshtab[];
  1147. Xextern  char    nam[];
  1148. Xextern  int     varshash[];
  1149. Xextern  int     chained;
  1150. X#ifndef MPORTABLE
  1151. Xextern  memp    enames;
  1152. X#endif
  1153. X#endif
  1154. X
  1155. Xextern  char    gblock[];
  1156. Xextern  int     gcursiz;
  1157. X
  1158. Xextern  (*functs[])();
  1159. Xextern  (*functb[])();
  1160. Xextern  (*strngcommand[])();
  1161. Xextern  (*commandf[])();
  1162. Xextern  char    *ermesg[];
  1163. Xextern  struct  tabl    table[];
  1164. X
  1165. X#endif
  1166. End of bas.h
  1167. chmod u=rw-,g=r,o=r bas.h
  1168. echo x - bas1.c 1>&2
  1169. sed 's/^X//' > bas1.c << 'End of bas1.c'
  1170. X/*
  1171. X * BASIC by Phil Cockcroft
  1172. X */
  1173. X/*
  1174. X *      This file contains the main routines of the interpreter.
  1175. X */
  1176. X
  1177. X
  1178. X/*
  1179. X *      the core is arranged as follows: -
  1180. X * -------------------------------------------------------------------  - - -
  1181. X * | file    |  text   |  string | user  | array |  simple    |  for/ | unused
  1182. X * | buffers |   of    |  space  | def   | space |  variables | gosub | memory
  1183. X * |         | program |         | fns   |       |            | stack |
  1184. X * -------------------------------------------------------------------  - - -
  1185. X * ^         ^         ^         ^       ^       ^            ^       ^
  1186. X * filestart fendcore  ecore     estring edefns  earray       vend    vvend
  1187. X *                        ^eostring           ^estarr
  1188. X */
  1189. X
  1190. X#define         PART1
  1191. X#include        "bas.h"
  1192. X#undef          PART1
  1193. X
  1194. X/*
  1195. X *      The main program , it sets up all the files, signals,terminal
  1196. X *      and pointers and prints the start up message.
  1197. X *      It then calls setexit().
  1198. X * IMPORTANT NOTE:-
  1199. X *              setexit() sets up a point of return for a function
  1200. X *      It saves the local environment of the calling routine
  1201. X *      and uses that environment for further use.
  1202. X *              The function reset() uses the information saved in
  1203. X *      setexit() to perform a non-local goto , e.g. poping the stack
  1204. X *      until it looks as though it is a return from setexit()
  1205. X *      The program then continues as if it has just executed setexit()
  1206. X *      This facility is used all over the program as a way of getting
  1207. X *      out of functions and returning to command mode.
  1208. X *      The one exception to this is during error trapping , The error
  1209. X *      routine must pop the stack so that there is not a recursive call
  1210. X *      on execute() but if it does then it looks like we are back in
  1211. X *      command mode. The flag ertrap is used to signal that we want to
  1212. X *      go straight on to execute() the error trapping code. The pointers
  1213. X *      must be set up before the execution of the reset() , (see error ).
  1214. X *              N.B. reset() NEVER returns , so error() NEVER returns.
  1215. X */
  1216. X
  1217. Xmain(argc,argv)
  1218. Xchar    **argv;
  1219. X{
  1220. X    register i;
  1221. X    catchsignal();
  1222. X    startfp();              /* start up the floating point hardware */
  1223. X    setupfiles(argc,argv);
  1224. X    setupterm();            /* set up files after processing files */
  1225. X    ecore = fendcore+sizeof(xlinnumb);
  1226. X    ( (lpoint) fendcore )->linnumb=0;
  1227. X    clear(DEFAULTSTRING);
  1228. X    prints("Phil's Basic version v1.8\n");
  1229. X    setexit();
  1230. X    if(ertrap)
  1231. X        goto execut;
  1232. X    docont();
  1233. X    runmode=0;              /* say we are in immeadiate mode */
  1234. X    if(cursor)              /* put cursor on a blank line */
  1235. X        prints(nl);
  1236. X    prints("Ready\n");
  1237. X    do{
  1238. X        do{
  1239. X            trapped=0;
  1240. X            *line ='>';
  1241. X            edit(1,1,1);
  1242. X        }while( trapped || ( !(i=compile(1)) && !linenumber ));
  1243. X        if(linenumber)
  1244. X            insert(i);
  1245. X    }while(linenumber);
  1246. X    if(inserted){
  1247. X        inserted=0;
  1248. X        clear(DEFAULTSTRING);
  1249. X        closeall();
  1250. X    }
  1251. X    vvend=bstk;             /* reset the gosub stack */
  1252. X    errortrap=0;            /* disable error traps */
  1253. X    intrap=0;               /* say we are not in the error trap */
  1254. X    trapped=0;              /* say we haven't got a cntrl-c */
  1255. X    cursor=0;               /* cursor is at start of line */
  1256. X    elsecount=0;            /* disallow elses as terminators */
  1257. X    curline=0;              /* current line is zero */
  1258. X    point=nline;            /* start executing at start of input line */
  1259. X    stocurlin=0;           /* start of current line is null- see 'next' */
  1260. Xexecut: execute();              /* execute the line */
  1261. X    return(-1);             /* see note below */
  1262. X}
  1263. X
  1264. X/*
  1265. X *      Execute will return by calling reset and so if execute returns then
  1266. X *    there is a catastrophic error and we should exit with -1 or something
  1267. X */
  1268. X
  1269. X/*
  1270. X *      compile converts the input line (in line[]) into tokenised
  1271. X *    form for execution(in nline). If the line starts with a linenumber
  1272. X *    then that is converted to binary and is stored in 'linenumber' N.B.
  1273. X *    not curline (see evalu() ). A linenumber of zero is assumed to
  1274. X *    be non existant and so the line is executed immeadiately.
  1275. X *      The parameter to compile() is an index into line that is to be
  1276. X *    ignored, e.g. the prompt.
  1277. X */
  1278. X
  1279. Xcompile(fl)
  1280. Xint     fl;
  1281. X{
  1282. X    register char   *p,*q;
  1283. X    register struct tabl    *l;
  1284. X    unsigned lin=0;
  1285. X    char    charac;
  1286. X    char    *eql(),*k;
  1287. X    p= &line[fl];
  1288. X    q=nline;
  1289. X    while(*p++ ==' ');
  1290. X    p--;
  1291. X    while(isnumber(*p)){                    /* get line number */
  1292. X        if(lin >= 6553)
  1293. X            error(7);
  1294. X        lin = lin*10 + (*p++ -'0');
  1295. X    }
  1296. X    while(*p==' ')
  1297. X        *q++ = *p++;
  1298. X    if(!*p){
  1299. X        linenumber =lin;
  1300. X        return(0);      /* no characters on the line */
  1301. X    }
  1302. X    while(*p){
  1303. X        if(*p=='"' || *p=='`'){         /* quoted strings */
  1304. X            charac= *p;
  1305. X            *q++ = *p++;
  1306. X            while(*p && *p != charac)
  1307. X                *q++ = *p++;
  1308. X            if(*p)
  1309. X                *q++= *p++;
  1310. X            continue;
  1311. X        }
  1312. X        if(*p < '<' && *p != '\''){     /* ignore all characters */
  1313. X            *q++ = *p++;            /* that couldn't be used */
  1314. X            continue;               /* in reserved words */
  1315. X        }
  1316. X        for(l=table ; l->string ; l++)  /* search the table */
  1317. X            if(*p != *(l->string) ) /* for the right entry */
  1318. X                continue;
  1319. X            else if(k = eql(p,l->string)){  /* if found then */
  1320. X#ifdef  LKEYWORDS
  1321. X                if( isletter(*p) ){
  1322. X                    if(p!= &line[fl] && isletter(*(p-1)) )
  1323. X                        continue;
  1324. X                    if( isletter(*k) && l->chval != FN)
  1325. X                        continue;
  1326. X                }
  1327. X#endif
  1328. X                *q++ = l->chval;    /* replace by a token */
  1329. X                p = k;
  1330. X                if(l->chval== REM || l->chval== QUOTE ||
  1331. X                            l->chval == DATA)
  1332. X                    while(*p)
  1333. X                        *q++ = *p++;
  1334. X                goto more;      /* dont compile comments */
  1335. X            }                       /* or data */
  1336. X        *q++ = *p++;
  1337. X    more:   ;
  1338. X    }
  1339. X    *q='\0';
  1340. X    linenumber=lin;
  1341. X    return(q-nline);                /* return length of line */
  1342. X}
  1343. X
  1344. X/*
  1345. X *      eql() returns true if the strings are the same .
  1346. X *    this routine is only called if the first letters are the same.
  1347. X *    hence the increment of the pointers , we don't need to compare
  1348. X *    the characters they point to.
  1349. X *      To increase speed this routine could be put into machine code
  1350. X *    the overheads on the function call and return are excessive
  1351. X *    for what it accomplishes. (it fails most of the time , and
  1352. X *    it can take a long time to load a large program ).
  1353. X */
  1354. X
  1355. Xchar    *
  1356. Xeql(p,q)
  1357. Xregister char   *p,*q;
  1358. X{
  1359. X    p++,q++;
  1360. X    while(*q)
  1361. X        if(*p++ != *q++){
  1362. X#ifdef  SCOMMS
  1363. X            if(*(p-1) == '.')
  1364. X                return(p);
  1365. X#endif
  1366. X            return(0);
  1367. X        }
  1368. X    return(p);
  1369. X}
  1370. X
  1371. X/*
  1372. X *      Puts a line in the table of lines then sets a flag (inserted) so that
  1373. X *    the variables are cleared , since it is very likely to have moved
  1374. X *    'ecore' and so the variables will all be corrupted. The clearing
  1375. X *    of the variables is not done in this routine since it is only needed
  1376. X *    to clear the variables once and that is best accomplished in main
  1377. X *    just before it executes the immeadiate mode line.
  1378. X *      If the line existed before this routine is called then it is deleted
  1379. X *    and then space is made available for the new line, which is then
  1380. X *    inserted.
  1381. X *      The structure of a line in memory has the following structure:-
  1382. X *              struct olin{
  1383. X *                      unsigned linnumb;
  1384. X *                      unsigned llen;
  1385. X *                      char     lin[1];
  1386. X *                      }
  1387. X *      The linenumber of the line is stored in linnumb , If this is zero
  1388. X *    then this is the end of the program (all searches of the line table
  1389. X *    terminate if it finds the linenumber is zero.
  1390. X *      The variable 'llen' is used to store the length of the line (in
  1391. X *    characters including the above structure and any padding needed to
  1392. X *    make the line an even length.
  1393. X *      To search through the table of lines then:-
  1394. X *              start at 'fendcore'
  1395. X *              IF linnumb is zero THEN terminate search
  1396. X *                ELSE IF linnumb is the required line THEN
  1397. X *                      found line , terminate
  1398. X *                ELSE
  1399. X *                      goto next line ( add llen to the current pointer )
  1400. X *                      repeat loop.
  1401. X *      The line is in fact stored in lin[] , To the C compiler this
  1402. X *    is a one character array but since the lines are more than one
  1403. X *    character long (usually) it is fooled into using it as a variable
  1404. X *    length array ( impossible in 'pure' C ).
  1405. X *      The pointers used by the program storage routines are:-
  1406. X *              fendcore = start of text storage segment
  1407. X *              ecore = end of text storage
  1408. X *                    = start of data segment (string space ).
  1409. X *    strings are stored after the text but before the numeric variables
  1410. X *    only 512 bytes are allocated at the start of the program for strings
  1411. X *    but clear can be called to get more core for the strings.
  1412. X */
  1413. X
  1414. Xinsert(lsize)
  1415. Xregister int    lsize;
  1416. X{
  1417. X    register lpoint p;
  1418. X    register unsigned l;
  1419. X    inserted=1;                  /* say we want the variables cleared */
  1420. X    l= linenumber;
  1421. X    for(p= (lpoint) fendcore ; p->linnumb; p=(lpoint)((memp)p+lenv(p)))
  1422. X        if(p->linnumb >= l ){
  1423. X            if(p->linnumb != l )
  1424. X                break;
  1425. X            l=lenv(p);      /* delete the old line */
  1426. X            bmov( (short *)p, (int)l);
  1427. X            ecore -= l;
  1428. X            break;
  1429. X        }
  1430. X    if(!lsize)                      /* line has no length */
  1431. X        return;
  1432. X    lsize += sizeof(struct olin);
  1433. X#ifdef  ALIGN4
  1434. X    lsize = (lsize + 03) & ~03;
  1435. X#else
  1436. X    if(lsize&01)
  1437. X        lsize++;                /* make length of line even */
  1438. X#endif
  1439. X    mtest(ecore+lsize);             /* get the core for it */
  1440. X    ecore += lsize;
  1441. X    bmovu( (short *)p,lsize);       /* make space for the line */
  1442. X    strcpy(nline,p->lin);           /* move the line into the space */
  1443. X    p->linnumb=linenumber;          /* give it a linenumber */
  1444. X    p->llen=lsize;                  /* give it its offset */
  1445. X}
  1446. X
  1447. X/*      This routine will move the core image down so deleteing a line */
  1448. X
  1449. Xbmov(a,b)
  1450. Xregister short  *a;
  1451. Xint     b;
  1452. X{
  1453. X    register short  *c,*d;
  1454. X    c= (short *)ecore;
  1455. X    d= (short *)((char *)a  + b );
  1456. X    do{
  1457. X        *a++ = *d++;
  1458. X    }while(d<c);
  1459. X}
  1460. X
  1461. X/*      This will move the text image up so that a new line can be inserted */
  1462. X
  1463. Xbmovu(a,b)
  1464. Xregister short  *a;
  1465. Xint     b;
  1466. X{
  1467. X    register short  *c,*d;
  1468. X    c= (short *) ecore;
  1469. X    d= (short *) (ecore-b);
  1470. X    do{
  1471. X        *--c = *--d;
  1472. X    }while(a<d);
  1473. X}
  1474. X
  1475. X/*
  1476. X *      The interpreter needs three variables to control the flow of the
  1477. X *    the program. These are:-
  1478. X *              stocurlin : This is the pointer to the start of the current
  1479. X *                          line it is used to index the next line.
  1480. X *                          If the program is in immeadiate mode then
  1481. X *                          this variable is NULL (very important for 'next')
  1482. X *              point:      This points to the current location that
  1483. X *                          we are executing.
  1484. X *              curline:    The current line number ( zero in immeadiate mode)
  1485. X *                          this is not needed for program exection ,
  1486. X *                          but is used in error etc. It could be made faster
  1487. X *                          if this variable is not used....
  1488. X */
  1489. X
  1490. X/*
  1491. X *      The main loop of the execution of a program.
  1492. X *      It does the following:-
  1493. X *              FOR(ever){
  1494. X *                      save point so that resume will go to the right place
  1495. X *                      IF cntrl-c THEN stop
  1496. X *                      IF NOT a reserved word THEN do_assignment
  1497. X *                              ELSE IF legal command THEN execute_command
  1498. X *                      IF return is NORMAL THEN
  1499. X *                              BEGIN
  1500. X *                                  IF terminator is ':' THEN continue
  1501. X *                                  ELSE IF terminator is '\0' THEN
  1502. X *                                         goto next line ; continue
  1503. X *                                  ELSE IF terminator is 'ELSE' AND
  1504. X *                                              'ELSES' are enabled THEN
  1505. X *                                                  goto next line ; continue
  1506. X *                              END
  1507. X *                      ELSE IF return is < NORMAL THEN continue
  1508. X *                                      ( used by goto etc. ).
  1509. X *                      ELSE IF return is > NORMAL THEN
  1510. X *                           ignore_rest_of_line ; goto next line ; continue
  1511. X *                      }
  1512. X *      All commands return a value ( if they return ). This value is NORMAL
  1513. X *    if the command is standard and does not change the flow of the program.
  1514. X *    If the value is greater than zero then the command wants to miss the
  1515. X *    rest of the line ( comments and data ).
  1516. X *      If the value is less than zero then the program flow has changed
  1517. X *    and so we should go back and try to execute the new command ( we are
  1518. X *    now at the start of a command ).
  1519. X */
  1520. X
  1521. Xexecute()
  1522. X{
  1523. X    register int    i,c;
  1524. X    register lpoint p;
  1525. X
  1526. X    ertrap=0;                       /* stop recursive error trapping */
  1527. Xagain:
  1528. X    savepoint=point;
  1529. X    if(trapped)
  1530. X        dobreak();
  1531. X    if(!((c=getch())&0200)){
  1532. X        point--;
  1533. X        assign();
  1534. X        goto retn;
  1535. X    }
  1536. X    if(c>=MAXCOMMAND)
  1537. X        error(8);
  1538. X    if((i=(*commandf[c&0177])())==NORMAL){  /* execute the command */
  1539. Xretn:           if((c=getch())==':')
  1540. X            goto again;
  1541. X        else if(!c){
  1542. Xelseret:                if(!runmode)            /* end of immeadiate line */
  1543. X                reset();
  1544. X            p = stocurlin;
  1545. X            p = (lpoint)((memp)p + lenv(p)); /* goto next line */
  1546. X            stocurlin=p;
  1547. X            point=p->lin;
  1548. X            if(!(curline=p->linnumb)) /* end of program */
  1549. X                reset();
  1550. X            elsecount=0;               /* disable `else`s */
  1551. X            goto again;
  1552. X        }
  1553. X        else  if(c==ELSE && elsecount)  /* `else` is a terminator */
  1554. X                goto elseret;
  1555. X        error(SYNTAX);
  1556. X    }
  1557. X    if(i < NORMAL)
  1558. X        goto again;     /* changed execution position */
  1559. X    else
  1560. X        goto elseret;   /* ignore rest of line */
  1561. X}
  1562. X
  1563. X/*
  1564. X *      The error routine , this is called whenever there is any error
  1565. X *    it does some tidying up of file descriptors and sets the error line
  1566. X *    number and the error code. If there is error trapping ( errortrap is
  1567. X *    non-zero and in runmode ), then save the old pointers and set up the
  1568. X *    new pointers for the error trap routine.
  1569. X *    Otherwise print out the error message and the current line if in
  1570. X *    runmode.
  1571. X *      Finally call reset() ( which DOES NOT return ) to pop
  1572. X *    the stack and to return to the main routine.
  1573. X */
  1574. X
  1575. Xerror(i)
  1576. Xint     i;                      /* error code */
  1577. X{
  1578. X    register lpoint p;
  1579. X    if(readfile){                   /* close file descriptor */
  1580. X        close(readfile);        /* from loading a file */
  1581. X        readfile=0;
  1582. X    }
  1583. X    if(pipes[0]){                   /* close the pipe (from chain ) */
  1584. X        close(pipes[0]);        /* if an error while chaining */
  1585. X        pipes[0]=0;
  1586. X    }
  1587. X    evallock=0;                     /* stop the recursive eval message */
  1588. X    ecode=i;                        /* set up the error code */
  1589. X    if(runmode)
  1590. X        elinnumb=curline;       /* set up the error line number */
  1591. X    else
  1592. X        elinnumb=0;
  1593. X    if(runmode && errortrap && !inserted ){ /* we have error trapping */
  1594. X        estocurlin=stocurlin;   /* save the various pointers */
  1595. X        epoint=savepoint;
  1596. X        eelsecount=elsecount;
  1597. X        p=errortrap;
  1598. X        stocurlin=p;            /* set up to execute code */
  1599. X        point=p->lin;
  1600. X        curline=p->linnumb;
  1601. X        saveertrap=p;           /* save errortrap pointer */
  1602. X        errortrap=0;            /* disable further error traps */
  1603. X        intrap=1;               /* say we are trapped */
  1604. X        ertrap=1;               /* we want to go to execute */
  1605. X    }
  1606. X    else  {                         /* no error trapping */
  1607. X        if(cursor){
  1608. X            prints(nl);
  1609. X            cursor=0;
  1610. X        }
  1611. X        prints(ermesg[i-1]);            /* error message */
  1612. X        if(runmode){
  1613. X            prints(" on line ");
  1614. X            prints(printlin(curline));
  1615. X        }
  1616. X        prints(nl);
  1617. X    }
  1618. X    reset();                /* no return - goes to main */
  1619. X}
  1620. X
  1621. X/*
  1622. X *      This is executed by the ON ERROR construct it checks to see
  1623. X *    that we are not executing an error trap then set up the error
  1624. X *    trap pointer.
  1625. X */
  1626. X
  1627. Xerrtrap()
  1628. X{
  1629. X    register lpoint p;
  1630. X    p=getline();
  1631. X    check();
  1632. X    if(intrap)
  1633. X        error(8);
  1634. X    errortrap=p;
  1635. X}
  1636. X
  1637. X/*
  1638. X *      The 'resume' command , checks to see that we are actually
  1639. X *    executing an error trap. If there is an optional linenumber then
  1640. X *    we resume from there else we resume from where the error was.
  1641. X */
  1642. X
  1643. Xresume()
  1644. X{
  1645. X    register lpoint p;
  1646. X    register unsigned i;
  1647. X    if(!intrap)
  1648. X        error(8);
  1649. X    i= getlin();
  1650. X    check();
  1651. X    if(i!= (unsigned)(-1) ){
  1652. X        for(p=(lpoint)fendcore;p->linnumb;p=(lpoint)((memp)p+lenv(p)))
  1653. X            if(p->linnumb==i)
  1654. X                goto got;
  1655. X        error(6);               /* undefined line */
  1656. Xgot:            stocurlin= p;                   /* resume at that line */
  1657. X        curline= p->linnumb;
  1658. X        point= p->lin;
  1659. X        elsecount=0;
  1660. X    }
  1661. X    else  {
  1662. X        stocurlin=estocurlin;          /* resume where we left off */
  1663. X        curline=elinnumb;
  1664. X        point=epoint;
  1665. X        elsecount=eelsecount;
  1666. X    }
  1667. X    errortrap=saveertrap;                   /* restore error trapping */
  1668. X    intrap=0;                               /* get out of the trap */
  1669. X    return(-1);                             /* return to re-execute */
  1670. X}
  1671. X
  1672. X/*
  1673. X *      The 'error' command , this calls the error routine ( used in testing
  1674. X *    an error trapping routine.
  1675. X */
  1676. X
  1677. Xdoerror()
  1678. X{
  1679. X    register i;
  1680. X    i=evalint();
  1681. X    check();
  1682. X    if(i<1 || i >MAXERR)
  1683. X        error(22);      /* illegal error code */
  1684. X    error(i);
  1685. X}
  1686. X
  1687. X/*
  1688. X *      This routine is used to clear space for strings and to reset all
  1689. X *    other pointers so that it effectively clears the variables.
  1690. X */
  1691. X
  1692. Xclear(stringsize)
  1693. Xint     stringsize;     /* size of string space */
  1694. X{
  1695. X#ifdef  LNAMES
  1696. X    register struct entry   **p;
  1697. X    register int    *ip;
  1698. X
  1699. X    for(p = hshtab ; p < &hshtab[HSHTABSIZ];)    /* clear the hash table*/
  1700. X        *p++ = 0;
  1701. X    for(ip = varshash ; ip < &varshash[HSHTABSIZ]; )
  1702. X        *ip++ = -1;
  1703. X#endif
  1704. X#ifdef  ALIGN4
  1705. X    estring= &ecore[stringsize& ~03];       /* allocate string space */
  1706. X#else
  1707. X    estring= &ecore[stringsize& ~01];       /* allocate string space */
  1708. X#endif
  1709. X    mtest(estring);                         /* get the core */
  1710. X    shash=1;                                /* string array "counter" */
  1711. X    datapoint=0;                           /* reset the pointer to data */
  1712. X    contpos=0;
  1713. X#ifdef  LNAMES
  1714. X    chained = 0;                            /* reset chained flag */
  1715. X    estdt=enames=edefns=earray=vend=bstk=vvend=estarr=estring;
  1716. X#else
  1717. X    estdt=edefns=earray=vend=bstk=vvend=estarr=estring;
  1718. X#endif
  1719. X            /* reset variable pointers */
  1720. X    eostring=ecore;                         /* string pointer */
  1721. X    srand(0);                               /* reset the random number */
  1722. X}                                               /* generator */
  1723. X
  1724. X/*
  1725. X *      mtest() is used to set the amount of core for the current program
  1726. X *    it uses brk() to ask the system for more core.
  1727. X *      The core is allocated in 1K chunks, this is so that the program does
  1728. X *    not spend most of is time asking the system for more core and at the
  1729. X *    same time does not hog more core than is neccasary ( be friendly to
  1730. X *    the system ).
  1731. X *      Any test that is less than 'ecore' is though of as an error and
  1732. X *    so is any test greater than the size that seven memory management
  1733. X *    registers can handle.
  1734. X *      If there is this error then a test is done to see if 'ecore' can
  1735. X *    be accomodated. If so then that size is allocated and error() is called
  1736. X *    otherwise print a message and exit the interpreter.
  1737. X *      If the value of the call is less than 'ecore' we have a problem
  1738. X *    with the interpreter and we should cry for help. (It doesn't ).
  1739. X */
  1740. X
  1741. Xmtest(l)
  1742. Xmemp    l;
  1743. X{
  1744. X    register memp   m;
  1745. X    static   memp   maxmem;                 /* pointer to top of memory */
  1746. X
  1747. X#ifdef  ALIGN4
  1748. X    if( (int)l & 03){
  1749. X        prints("Illegal allignment\n");
  1750. X        quit();
  1751. X    }
  1752. X#endif
  1753. X    m = (memp)(((int)l+MEMINC)&~MEMINC);    /* round the size up */
  1754. X    if(m==maxmem)                           /* if allocated then return */
  1755. X        return;
  1756. X    if(m < ecore || m > MAXMEM || brk(m) == -1){ /* problems*/
  1757. X        m= (memp) (((int)ecore +DEFAULTSTRING+MEMINC )&~MEMINC);
  1758. X        if(m <= MAXMEM && brk(m)!= -1){
  1759. X            maxmem= m;              /* oh, safe */
  1760. X            clear(DEFAULTSTRING);   /* zap all pointers */
  1761. X            error(24);              /* call error */
  1762. X        }
  1763. X        prints("out of core\n");        /* print message */
  1764. X        quit();                         /* exit flushing buffers */
  1765. X    }
  1766. X    maxmem=m;                               /* set new limit */
  1767. X}
  1768. X
  1769. X/*
  1770. X *      This routine is called to test to see if there is enough space
  1771. X *    for an array. The result is true if there is no space left.
  1772. X */
  1773. X
  1774. Xnospace(l)
  1775. Xlong    l;
  1776. X{
  1777. X#ifndef pdp11
  1778. X    if(l< 0 || vvend+l >= MAXMEM)
  1779. X#else
  1780. X    if(l< 0 || l >65535L || (long)vvend+l >= 0160000L)
  1781. X#endif
  1782. X        return(1);
  1783. X    return(0);      /* we have space */
  1784. X}
  1785. X
  1786. X/*
  1787. X *      This routine is called by the routines that define variables
  1788. X *    to increase the amount of space that is allocated between the
  1789. X *    two end pointers of that 'type'. It uses the fact that all the
  1790. X *    variable pointers are in a certain order (see bas.h ). It
  1791. X *    increments the relevent pointers and then moves up the rest of
  1792. X *    the data to a new position. It also clears the area that it
  1793. X *    has just allocated and then returns a pointer to the space.
  1794. X */
  1795. X
  1796. Xmemp xpand(start,size)
  1797. Xregister memp   *start;
  1798. Xint     size;
  1799. X{
  1800. X    register short  *p,*q;
  1801. X    short   *bottom;
  1802. X    bottom = (short *) (*start);
  1803. X    p= (short *)vvend;
  1804. X    do{
  1805. X        *start++ += size;
  1806. X    }while( start <= &vvend);
  1807. X    mtest(vvend);
  1808. X    start= (memp *)bottom;
  1809. X    q= (short *)vvend;
  1810. X    do{
  1811. X        *--q = *--p;
  1812. X    }while(p > (short *)start);
  1813. X    do{
  1814. X        *--q=0;
  1815. X    }while(q > (short *)start);
  1816. X    return( (memp) start);
  1817. X}
  1818. X
  1819. X/*
  1820. X *      This routine tries to set up the system to catch all the signals that
  1821. X *    can be produced. (except kill ). and do something sensible if it
  1822. X *    gets one. ( There is no way of producing a core image through the
  1823. X *    sending of signals).
  1824. X */
  1825. X
  1826. X#ifdef  V6
  1827. X#define _exit   exit
  1828. X#endif
  1829. X
  1830. Xcatchsignal()
  1831. X{
  1832. X    extern  _exit(),quit1(),catchfp();
  1833. X#ifdef  SIGTSTP
  1834. X    extern  onstop();
  1835. X#endif
  1836. X    register int    i;
  1837. X    static  int     (*traps[NSIG])()={
  1838. X        quit,           /* hang up */
  1839. X        trap,           /* cntrl-c */
  1840. X        quit1,          /* cntrl-\ */
  1841. X        _exit,
  1842. X        _exit,
  1843. X        _exit,
  1844. X        _exit,
  1845. X        catchfp,        /* fp exception */
  1846. X        0,              /* kill    */
  1847. X        seger,          /* seg err */
  1848. X        mcore,          /* bus err */
  1849. X        0,
  1850. X        _exit,
  1851. X        _exit,
  1852. X        _exit,
  1853. X        _exit,
  1854. X        _exit,
  1855. X        };
  1856. X
  1857. X    for(i=1;i<NSIG;i++)
  1858. X        signal(i,traps[i-1]);
  1859. X#ifdef  SIGTSTP
  1860. X    signal(SIGTSTP,onstop);         /* the stop signal */
  1861. X#endif
  1862. X}
  1863. X
  1864. X/*
  1865. X *      this routine deals with floating exceptions via fpfunc
  1866. X *    this is a function pointer set up in fpstart so that trapping
  1867. X *    can be done for floating point exceptions.
  1868. X */
  1869. X
  1870. Xcatchfp()
  1871. X{
  1872. X    extern  (*fpfunc)();
  1873. X
  1874. X    signal(SIGFPE,catchfp); /* restart catching */
  1875. X    if(fpfunc== 0)          /* this is set up in fpstart() */
  1876. X        _exit(1);
  1877. X    (*fpfunc)();
  1878. X}
  1879. X
  1880. X/*
  1881. X *      we have a segmentation violation and so should print the message and
  1882. X *    exit. Either a kill() from another process or an interpreter bug.
  1883. X */
  1884. X
  1885. Xseger()
  1886. X{
  1887. X    prints("segmentation violation\n");
  1888. X    _exit(-1);
  1889. X}
  1890. X
  1891. X/*
  1892. X *      This does the same for bus errors as seger() does for segmentation
  1893. X *    violations. The interpreter is pretty nieve about the execution
  1894. X *    of complex expressions and should really check the stack every time,
  1895. X *    to see if there is space left. This is an easy error to fix, but
  1896. X *    it was not though worthwhile at the moment. If it runs out of stack
  1897. X *    space then there is a vain attempt to call mcore() that fails and
  1898. X *    so which produces another bus error and a core image.
  1899. X */
  1900. X
  1901. Xmcore()
  1902. X{
  1903. X    prints("bus error\n");
  1904. X    _exit(-1);
  1905. X}
  1906. X
  1907. X/*
  1908. X *      Called by the cntrl-c signal (number 2 ). It sets 'trapped' to
  1909. X *    signify that there has been a cntrl-c and then re-enables the trap.
  1910. X *      It also bleeps at you.
  1911. X */
  1912. X
  1913. Xtrap()
  1914. X{
  1915. X    signal(SIGINT, SIG_IGN);/* ignore signal for the bleep */
  1916. X    write(1, "\07", 1);     /* bleep */
  1917. X    signal(SIGINT, trap);   /* re-enable the trap */
  1918. X    trapped=1;              /* say we have had a cntrl-c */
  1919. X#ifdef  BSD42
  1920. X    if(ecalling){
  1921. X        ecalling = 0;
  1922. X        longjmp(ecall, 1);
  1923. X    }
  1924. X#endif
  1925. X}
  1926. X
  1927. X/*
  1928. X *      called by cntrl-\ trap , It prints the message and then exits
  1929. X *    via quit() so flushing the buffers, and getting the terminal back
  1930. X *    in a sensible mode.
  1931. X */
  1932. X
  1933. Xquit1()
  1934. X{
  1935. X    signal(SIGQUIT,SIG_IGN);/* ignore any more */
  1936. X    if(cursor){             /* put cursor on a new line */
  1937. X        prints(nl);
  1938. X        cursor=0;
  1939. X    }
  1940. X    prints("quit\n\r");     /* print the message */
  1941. X    quit();                 /* exit */
  1942. X}
  1943. X
  1944. X/*
  1945. X *      resets the terminal , flushes all files then exits
  1946. X *    this is the standard route exit from the interpreter. The seger()
  1947. X *    and mcore() traps should not go through these traps since it could
  1948. X *    be the access to the files that is causing the error and so this
  1949. X *    would produce a core image.
  1950. X *      From this it may be gleened that I don't like core images.
  1951. X */
  1952. X
  1953. Xquit()
  1954. X{
  1955. X    flushall();                     /* flush the files */
  1956. X    rset_term(1);
  1957. X    if(cursor)
  1958. X        prints(nl);
  1959. X    exit(0);                       /* goodbye */
  1960. X}
  1961. X
  1962. Xdocont()
  1963. X{
  1964. X    if(runmode){
  1965. X        contpos=0;
  1966. X        if(cancont){
  1967. X            bstk= vvend;
  1968. X            contpos=cancont;
  1969. X        }
  1970. X        else
  1971. X            bstk= vend;
  1972. X    }
  1973. X    cancont=0;
  1974. X}
  1975. X
  1976. X#ifdef  SIGTSTP
  1977. X/*
  1978. X * support added for job control
  1979. X */
  1980. Xonstop()
  1981. X{
  1982. X    flushall();                     /* flush the files */
  1983. X    if(cursor){
  1984. X        prints(nl);
  1985. X        cursor = 0;
  1986. X    }
  1987. X#ifdef  BSD42
  1988. X    sigsetmask(0);                  /* Urgh !!!!!! */
  1989. X#endif
  1990. X    signal(SIGTSTP, SIG_DFL);
  1991. X    kill(0,SIGTSTP);
  1992. X    /* The PC stops here */
  1993. X    signal(SIGTSTP,onstop);
  1994. X}
  1995. X#endif
  1996. End of bas1.c
  1997. chmod u=rw-,g=r,o=r bas1.c
  1998.  
  1999.