karel 1.0
Jan Miksovsky '86 off
jtm at spock.UUCP
Sun Nov 17 01:57:47 AEST 1985
Last year, I wrote an interpreter for the Karel language to help introduce
students here taking structured programming courses. The language is
very simple, but is more fun for new programmers to use than Pascal since it
is more visually-oriented. I'm running this on a VAX 11/750 under 4.2 BSD,
and I haven't found any problems (yet :-) .
Mail comments, bug reports, suggestions, etc. to me, *please*.
A demo program, maze.k, is enclosed. To run it, type "karel maze.k" and
press the return key after the maze is loaded in.
Enjoy.
Jan Miksovsky
Choate Rosemary Hall
P.O. Box 788
Wallingford, CT 06492
...{decvax}!yale!spock!jtm
# -----------------CUT HERE---------------------
#!/bin/sh
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# wrapped by spock!jtm on Wed Nov 6 12:03:55 EST 1985
echo x - README
sed 's/^X//' > README << !SHAR!EOF!
XThis is version 1.0 of an interpreter for Karel's programming language as
Xdescribed in "Karel the Robot" by Richard E. Pattis (John Wiley & Sons, 1981).
XThe language is described as a "gentle introduction to Pascal"; while very
Xsimple, it teaches the basics of structured programming.
XN.B. This is *not* the interpreter that Pattis wrote (the one described in the
Xbook), which is copyright. This version was written independently; approval
Xwas obtained from him for this posting. Right is hereby given for unlimited
Xnon-profit use of this particular package.
X
XThe structure of this interpreter is based heavily on that of hoc(1), described
Xin "The Unix Programming Environment" by Brian Kernighan and Rob Pike; anyone
Xinterested in the "guts" of this program should be familiar with that program.
X
X******************************************************************************
X
XFile Contents
X
Xcode.c program executor and run-time routines
Xdoc short BNF-like language description
Xhelp.h help-screen information
Xkarel.1 manual page
Xkarel.h global declarations
Xkarel.y syntactical language definition
Xklex.c lexical analyzer
Xmain.c startup routines, error handlers, etc.
Xscr.c screen routines
Xsymbol.c symbol-table manipulator
Xwords.h Karel keywords and built-in procedures
X
X******************************************************************************
X
X
X Jan Miksovsky
X Choate Rosemary Hall
X P.O. Box 788
X Wallingford, CT 06492
X
X ...{decvax}!yale!spock!jtm
X
!SHAR!EOF!
echo x - makefile
sed 's/^X//' > makefile << !SHAR!EOF!
X# makefile for karel 1.0 11/6/85
X
XOBJS = main.o klex.o symbol.o code.o y.tab.o scr.o
X
Xkarel: $(OBJS)
X cc $(CFLAGS) $(OBJS) -o karel -lcurses -ltermcap
X
X$(OBJS): karel.h
X
Xklex.o: words.h
X
Xwords.h: y.tab.h
X
Xy.tab.c y.tab.h: karel.y
X yacc -d karel.y
X
Xscr.o: help.h
!SHAR!EOF!
echo x - code.c
sed 's/^X//' > code.c << !SHAR!EOF!
X#include <stdio.h>
X#include "karel.h"
X#include "y.tab.h"
X
X/* NPROG is size of program; no one would ever write a program this large */
X#define NPROG 500
X
X#define advpc ++pc
X#define nextinst prog[advpc]
X
XInst prog[NPROG]; /* the machine */
Xint progp; /* next spot for code */
Xint pc; /* program counter */
Xint startaddr; /* start of main block */
Xint flag; /* flag for logic tests */
Xint dest; /* branch destination */
X
Xinitcode() /* set up counters, etc., for execution */
X{
X progp = 0;
X flag = 0;
X pc = 0;
X}
X
Xsetcode(addr, n) /* install one program instruction */
Xint addr;
XInst n;
X{
X prog[addr] = n;
X}
X
Xsetcodeint(addr, n) /* install one int */
Xint addr, n;
X{
X prog[addr] = (Inst) n;
X}
X
Xcode(n) /* install next instruction */
XInst n;
X{
X if (progp >= NPROG)
X severe("program too big", (char *) 0);
X setcode(progp++, n);
X}
X
Xcodeint(n) /* install a int as next instruction */
Xint n;
X{
X code((Inst) n);
X}
X
Xexecute(n) /* execute machine */
Xint n;
X{
X int temp;
X
X temp = pc;
X for (pc = n; (prog[pc] != RETURN) && state; pc++) {
X (*(prog[pc]))();
X update();
X }
X pc = temp;
X}
X
Xturnleft() /* turn karel 90 degrees left */
X{
X if (--dir < 0)
X dir = 3;
X placekarel(y, x);
X}
X
Xbranch() /* jump to another instruction */
X{
X dest = (int) nextinst;
X pc = dest - 1;
X}
X
Xcondbranch() /* jump of last logic test was false */
X{
X if (!flag)
X branch();
X else
X advpc;
X}
X
Xcall() /* call a user-defined instruction */
X{
X execute(nextinst);
X}
X
Xloopexec() /* execute block of code a number of times */
X{
X int k, limit, loopbody;
X
X limit = (int) nextinst;
X loopbody = pc + 2;
X for (k = 0; k < limit; k++)
X execute(loopbody);
X branch();
X}
X
Xturnoff() /* end program execution */
X{
X state = OFF;
X}
X
X/* code for built-in logical test */
X
Xanybeepers() { flag = beepers; }
Xfacingeast() { flag = (dir == 1); }
Xfacingnorth() { flag = (dir == 0); }
Xfacingsouth() { flag = (dir == 2); }
Xfacingwest() { flag = (dir == 3); }
Xfrontblocked() { flag = !sideclear(dir); }
Xfrontclear() { flag = sideclear(dir); }
Xleftblocked() { flag = !sideclear(dir-1); }
Xleftclear() { flag = sideclear(dir-1); }
Xnobeepers() { flag = !beepers; }
Xnotfacingeast() { flag = (dir != 1); }
Xnotfacingnorth() { flag = (dir != 0); }
Xnotfacingsouth() { flag = (dir != 2); }
Xnotfacingwest() { flag = (dir != 3); }
Xrightblocked() { flag = !sideclear(dir+1); }
Xrightclear() { flag = sideclear(dir+1); }
X
Xnexttobeeper()
X{
X flag = (oldch == '*' || (oldch >= '0' && oldch <= '9'));
X}
X
Xnotnexttobeeper()
X{
X nexttobeeper();
X flag = !flag;
X}
!SHAR!EOF!
echo x - doc
sed 's/^X//' > doc << !SHAR!EOF!
X
X
XThe following is a list of statements available in the Karel language...
X
X
Xprimitive instructions:
X move Karel moves one block forward
X turnleft pivots 90 degrees left
X pickbeeper puts beeper in beeper-bag
X putbeeper puts beeper on corner
X turnoff turns off
X
Xblock structure words:
X BEGIN
X <stmt>;
X <stmt>;
X <stmt>;
X ...
X END;
X
X IF <test>
X THEN <stmt>
X [ ELSE <stmt> ]
X
X ITERATE <positive-integer> TIMES
X <stmt>
X
X WHILE <test> DO
X <stmt>
X
X DEFINE-NEW-INSTRUCTION <name> AS
X <stmt>
X
X BEGINNING-OF-PROGRAM
X <definitions>
X BEGINNING-OF-EXECUTION
X <stmt>;
X <stmt>;
X <stmt>;
X ...
X END-OF-EXECUTION
X END-OF-PROGRAM
X
Xtests:
X front-is-clear, front-is-blocked,
X left-is-clear, left-is-blocked,
X right-is-clear, right-is-blocked,
X next-to-a-beeper, not-next-to-a-beeper,
X facing-north, not-facing-north,
X facing-south, not-facing-south,
X facing-east, not-facing-east,
X facing-west, not-facing-west,
X any-beepers-in-beeper-bag,
X no-beepers-in-beeper-bag
X
Xcomments:
X This version of karel uses Pascal-style "{" and "}" comment
X delimiters; this is the only addition to the language described
X in "Karel the Robot"
!SHAR!EOF!
echo x - help.h
sed 's/^X//' > help.h << !SHAR!EOF!
X/* messages for help screen */
X
Xchar *helpmsg[] = {
X "Key Commands:\n",
X "i\tmove north",
X "j\t west",
X "k\t east",
X "m\t south\n",
X "I\tplace Karel facing north",
X "J\t west",
X "K\t east",
X "M\t south\n",
X "o\tplace wall section",
X "q\tquit",
X "s\tsave screen",
X "S\tsave snapshot\n",
X "*\tplace beeper",
X "?\tprint this screen",
X "return\trun program",
X "space\terase an object\n",
X 0
X};
!SHAR!EOF!
echo x - karel.1
sed 's/^X//' > karel.1 << !SHAR!EOF!
X.TH KAREL 1 "Choate Rosemary Hall"
X.UC 4
X.SH NAME
Xkarel \- interpreter for Karel's programming language
X.SH SYNOPSIS
X.br
X.B karel
X[
X.B \-n
X]
X[
X.B \-b
Xbeepers
X]
Xfile.k
X.br
X.SH DESCRIPTION
X.I Karel
Xis an interpreter for Karel's programming language, an introductory language
Xbased on the structure of Pascal, which incorporates some of the visual
Xfeedback possible from languages like Logo.
X.PP
XAfter reading the specified program (with a name ending in ".k"), a
Xscreen with a corresponding name (ending in ".scr") is read if it exists.
XThe screen editor is then called; from there, you can place Karel, the
Xrobot, on the screen, and then run the program by pressing the return key.
X.PP
XThe following flags are recognized by
X.I karel:
X.TP 8
X.B \-b
XSets the number of beepers Karel will be holding at the start of program
Xexecution (default is zero).
X.br
X.TP 8
X.B \-n
XSuppress loading of screen file
X.br
X.TP 0
X.nf
XThe following is a list of the screen editor commands:
X
Xi move cursor north (up)
Xj west (left)
Xk east (right)
Xm south (down)
X
XI place Karel facing north
XJ west
XK east
XM south
X
Xo place wall section
Xq quit; end execution of karel
Xs save screen as file with suffix '.scr'
XS save picture of screen with borders, saved as 'snapshot'
X
X* place beeper
X? print help screen
Xreturn run program
Xspace erase an object
X.fi
X.PP
XNote: after running program, press ESC to leave screen setup as it is, or press
Xany other key to reset screen to setup before program execution.
X.br
X.SH FILES
Xfile.k source program
X.br
Xfile.scr picture of screen, without borders
X.br
Xsnapshot picture of screen, with borders
X.br
X.SH SEE\ ALSO
XPattis, Richard E.;
X.ul 1
XKarel the Robot
X.br
X.SH AUTHOR
XJan Miksovsky
X.SH BUGS
XSome of the "features" of this interpreter are superfluous: e.g., the
Xdashed lines which serve no purpose other than to make the screen look
Xlike the pictures in the book.
!SHAR!EOF!
echo x - karel.h
sed 's/^X//' > karel.h << !SHAR!EOF!
X/* file name suffixes */
X#define PROGSUFFIX "k"
X#define SCRSUFFIX "scr"
X
X/* interpreter states */
X#define OFF 0
X#define COMPILE 1
X#define EDIT 2
X#define RUN 3
X
Xtypedef int (*Inst)(); /* pseudo-compiled instruction */
X
X/* marks end of procedure or main block */
X#define RETURN (Inst) 0
X
Xtypedef struct Bltintype { /* built-in procedure entry */
X char *name;
X Inst func;
X int type;
X} Bltintype;
X
Xtypedef struct Symbol { /* symbol table entry */
X char *name;
X int addr;
X struct Symbol *next;
X} Symbol;
X
X/* in main.c */
Xextern nflg, state;
Xextern severe(), err(), interupt(), screrror();
Xextern char *progname, basename[];
X
X/* in words.h */
Xextern Bltintype bltins[];
X
X/* in symbol.c */
Xextern Symbol *symtab, *lookup();
Xextern install();
X
X/* in klex.c */
Xextern nkeys, gotsemcolon, gotturnoff, linecount, tokenid, yyval;
Xextern yylex(), printdump();
Xextern char yytext[];
X
X/* in code.c */
Xextern progp, startaddr, initcode(), setcode(), code(), execute();
Xextern anybeepers(), facingeast(), facingnorth(), facingsouth();
Xextern facingwest(), frontblocked(), frontclear(), leftblocked();
Xextern leftclear(), nexttobeeper(), nobeepers();
Xextern notfacingeast(), notfacingnorth(), notfacingsouth(), notfacingwest();
Xextern notnexttobeeper(), pickbeeper(), putbeeper(), rightblocked();
Xextern rightclear(), turnleft(), turnoff();
X
X/* in scr.c */
Xextern beepers, dir, x, y, editscr(), reset(), placekarel(), putbeeper();
Xextern pickbeeper(), movekarel(), sideclear(), update(), finish();
Xextern readscrn(), initialize(), shutoff();
Xextern char oldch;
!SHAR!EOF!
echo x - karel.y
sed 's/^X//' > karel.y << !SHAR!EOF!
X%{
X
X#include <stdio.h>
X#include "karel.h"
X
Xextern int condbranch(), branch(), call(), bltin(), loopexec();
Xchar instname[BUFSIZ];
XSymbol *sp;
X
X%}
X
X%start prog
X /* Karel keywords */
X
X%token AS BEGEXEC BEGIN BEGPROG DEFINST DO ELSE END ENDEXEC
X%token ENDPROG IF ITERATE THEN TIMES WHILE
X
X /* interpreter types */
X
X%token KEY BLTIN TEST NUMBER NAME
X
X
X%% /* beginning of rules */
X
X
Xprog : BEGPROG deflist begexec stmtlist ENDEXEC ENDPROG {
X startaddr = \$3;
X code(RETURN);
X }
X | prog error
X { yyerrok; }
X ;
X
Xbegexec : BEGEXEC {
X strcpy(instname, "");
X fprintf(stderr, "main block:\n");
X \$\$ = progp;
X }
X ;
X
Xdeflist : def
X | deflist ';' def
X ;
X
Xdef : /* nothing */
X | definst AS stmt
X { code(RETURN); }
X ;
X
Xdefinst : DEFINST NAME {
X strcpy(instname, yytext);
X fprintf(stderr, "%s:\n", instname);
X install(instname);
X }
X | DEFINST BLTIN
X { err("tried to redefine primitive instruction:",
X yytext); }
X | DEFINST TEST
X { err("tried to redefine logical test:", yytext); }
X ;
X
Xstmtlist : stmt
X | stmtlist ';' stmt
X ;
X
Xstmt : BEGIN stmtlist END
X | IF logictest THEN stmt {
X setcode(\$2 + 1, condbranch);
X setcodeint(\$2 + 2, progp);
X }
X | IF logictest THEN stmt else stmt {
X setcode(\$2 + 1, condbranch);
X setcodeint(\$2 + 2, \$5 + 1);
X setcodeint(\$5, progp);
X }
X | iterate TIMES stmt {
X code(RETURN);
X setcodeint(\$1, progp);
X }
X | WHILE logictest DO stmt {
X setcode(\$2 + 1, condbranch);
X setcodeint(\$2 + 2, progp + 2);
X code(branch);
X codeint(\$2);
X }
X | NAME {
X if ((sp = lookup(yytext)) == (Symbol *) 0)
X err(yytext, "undefined");
X else {
X if (strcmp(yytext, instname) == 0)
X err("recursive procedure call:",
X yytext);
X else {
X code(call);
X codeint(sp->addr);
X }
X }
X }
X | BLTIN {
X if (strcmp(yytext, "turnoff") == 0)
X gotturnoff = 1;
X code(bltins[tokenid].func);
X }
X | error
X ;
X
Xlogictest : TEST {
X \$\$ = progp;
X code(bltins[tokenid].func);
X codeint(0); /* leave room for branch */
X codeint(0); /* instruction and address */
X }
X | NAME
X { err("invalid logical test:", yytext); }
X | BLTIN
X { err("invalid logical test:", yytext); }
X ;
X
Xelse : ELSE {
X code(branch);
X \$\$ = progp;
X codeint(0);
X };
X
Xiterate : ITERATE NUMBER {
X code(loopexec);
X codeint(atoi(yytext));
X \$\$ = progp;
X codeint(0);
X }
X ;
!SHAR!EOF!
echo x - klex.c
sed 's/^X//' > klex.c << !SHAR!EOF!
X#include <stdio.h>
X#include <ctype.h>
X#include "karel.h"
X#include "words.h"
X
Xint nkeys, nbltins; /* number of keywords and bltins */
Xint gotsemcolon;
Xint gotturnoff;
Xint tokenid; /* token number */
Xint linecount; /* no. of lines in input */
Xint yyval;
Xchar yytext[BUFSIZ];
Xstatic char c; /* character being handled */
Xextern FILE *fp; /* source file; found in main.c */
X
Xinitlex() /* prepare the lexical analyzer */
X{
X /* count the number of keywords */
X for (nkeys = 0; keywords[nkeys].name; nkeys++)
X ;
X for (nbltins = 0; bltins[nbltins].name; nbltins++)
X ;
X c = ' ';
X}
X
Xchar egetc(fp) /* get a character, checking for EOF */
XFILE *fp;
X{
X char c;
X
X if ((c = getc(fp)) == EOF)
X severe("unexpected end of program");
X else
X return(c);
X}
X
Xyylex() /* lexical analyzer */
X{
X int len; /* length of word */
X int n; /* temporary */
X
X skipwhite();
X while (c == '{') { /* skip over comment */
X while (c != '}')
X c = egetc(fp);
X c = getc(fp);
X skipwhite();
X }
X len = 0;
X while (isalnum(c) || c == '-') { /* read one word */
X yytext[len++] = c;
X c = getc(fp);
X }
X yytext[len] = '\0'; /* mark end of word */
X if (len > 0 && c != EOF) {
X tokenid = getkeyid(yytext);
X if (tokenid >= 0)
X yyval = keywords[tokenid].keyid;
X else {
X tokenid = getbltinid(yytext);
X if (tokenid >= 0)
X yyval = bltins[tokenid].type;
X else
X yyval = sscanf(yytext, "%d", &n) ? NUMBER:NAME;
X }
X }
X else {
X yyval = c;
X c = getc(fp);
X }
X return(yyval);
X}
X
Xgetkeyid(s) /* find s in keyword array; return -1 if not found */
Xchar *s;
X{
X int cmp, lower, upper, guess, found;
X
X /* use a binary search */
X found = lower = 0;
X upper = nkeys;
X while (lower <= upper && !found) {
X if (!(cmp = strcmp(s, keywords[guess=(lower+upper)/2].name)))
X found = 1;
X else
X if (cmp > 0)
X lower = guess + 1;
X else
X upper = guess - 1;
X }
X return(found ? guess : -1);
X}
X
X
X/* this is sort of redundant, but I didn't want to pass two kinds of */
X/* arrays to the same search routine */
X
X
Xgetbltinid(s) /* find s in built-in array; return -1 if not found */
Xchar *s;
X{
X int cmp, lower, upper, guess, found;
X
X /* use a binary search */
X found = lower = 0;
X upper = nbltins;
X while (lower <= upper && !found) {
X if (!(cmp = strcmp(s, bltins[guess=(lower+upper)/2].name)))
X found = 1;
X else
X if (cmp > 0)
X lower = guess + 1;
X else
X upper = guess - 1;
X }
X return(found ? guess : -1);
X}
X
Xskipwhite() /* skip over white space (tabs, etc.) */
X{
X while (isspace(c)) {
X if (c == '\n')
X linecount++;
X c = getc(fp);
X }
X}
!SHAR!EOF!
echo x - main.c
sed 's/^X//' > main.c << !SHAR!EOF!
X
X/*
X * karel: interpreter for Karel's programming language
X *
X * version 1.0, completed November 6th, 1985
X * by J.T.Miksovsky @ Choate Rosemary Hall
X *
X * N.B. This is *not* the interpreter that Richard E. Pattis wrote (the one
X * described in his book, "Karel the Robot"). Approval from the Pattis was
X * obtained for this distribution.
X *
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include "karel.h"
X
Xint nflg; /* -n (no screen load) option flag */
Xint errfound; /* 1 if a syntax or lexical error found */
Xint state; /* tells if compiling, running, etc. */
Xchar *progname; /* name of this program */
Xchar filename[BUFSIZ]; /* name of the source file */
Xchar basename[BUFSIZ]; /* name of source without suffix */
Xchar *usage = "usage: karel [-n] [-b beepers] file.k\n";
XFILE *fp; /* source file */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X progname = *argv;
X state = COMPILE;
X beepers = 0;
X /* process arguments */
X nflg = 0;
X argc--;
X argv++;
X while (argc > 0 && **argv == '-') {
X (*argv)++;
X while (**argv)
X switch (*(*argv)++) {
X case 'b':
X if (**argv == '\0') {
X argc--;
X argv++;
X }
X if (sscanf(*argv, "%d",&beepers) != 1)
X syserr("bad beeper number",0);
X if (beepers < 0)
X syserr("bad beeper number",0);
X **argv = '\0';
X break;
X case 'n':
X nflg = 1;
X break;
X default:
X fprintf(stderr, usage);
X exit(1);
X break;
X }
X argc--;
X argv++;
X }
X if (argc != 1) {
X fprintf(stderr, usage);
X exit(1);
X }
X dofiles(*argv);
X /* set up for parsing */
X errfound = 0;
X gotsemcolon = 0;
X gotturnoff = 0;
X linecount = 1;
X initlex();
X initcode();
X yyparse();
X fclose(fp);
X if (!gotturnoff && !errfound)
X severe("no turnoff instruction found", NULL);
X if (!errfound) {
X fprintf(stderr, "\tno lexical or syntatic errors\n");
X /* prepare to call screen editor */
X state = EDIT;
X initialize();
X if (!nflg)
X readscrn();
X editscr();
X }
X else
X fprintf(stderr,
X "Execution suppressed due to compilation errors\n");
X}
X
X/* there are many error handlers to handle many type of errors */
X
Xsyserr(s, t) /* system error: print error message and die */
Xchar *s, *t;
X{
X if (state != COMPILE)
X finish();
X fprintf(stderr, "%s: %s", progname, s);
X if (t)
X fprintf(stderr, "%s", t);
X fputc('\n', stderr);
X exit(1);
X}
X
Xsevere(s, t) /* print error message and die */
Xchar *s, *t;
X{
X fprintf(stderr, "%s", s);
X if (t)
X fprintf(stderr, " %s", t);
X fprintf(stderr, "\ncannot recover from previous errors -- QUIT\n");
X exit(1);
X}
X
Xerr(s, t) /* print error message */
Xchar *s, *t;
X{
X errfound = 1;
X fprintf(stderr, "\t%s", s);
X if (t)
X fprintf(stderr, " %s", t);
X fprintf(stderr, ", line %d\n", linecount);
X}
X
Xyyerror(s) /* handle parser error */
Xchar *s;
X{
X errfound = 1;
X fprintf(stderr, "\t%s, line %d", s, linecount);
X if (yytext[0])
X fprintf(stderr, " near %s", yytext);
X fputc('\n', stderr);
X}
X
Xinterupt() /* handle interupts, die */
X{
X signal(SIGINT, SIG_IGN);
X finish();
X fprintf(stderr, "interupt\n");
X exit(0);
X}
X
Xscrerror(s) /* reset terminal modes, die */
Xchar *s;
X{
X reset();
X fprintf(stderr, "\nscreen error: %s\n", s);
X exit(1);
X}
X
Xdofiles(s) /* get filename, open files, etc. */
Xchar *s;
X{
X int suffstart;
X char suffix[10];
X
X /* check suffix */
X strcpy(suffix, ".");
X strcat(suffix, PROGSUFFIX);
X suffstart = strlen(s) - strlen(suffix);
X if (strcmp(s + suffstart, suffix) != 0)
X syserr("bad filename: ", s);
X s[suffstart] = '\0'; /* delete suffix */
X strcpy(basename, s);
X sprintf(filename, "%s.%s", basename, PROGSUFFIX);
X if ((fp = fopen(filename, "r")) == NULL)
X syserr("can't open file: ", s);
X}
!SHAR!EOF!
echo x - scr.c
sed 's/^X//' > scr.c << !SHAR!EOF!
X#include <stdio.h>
X#include <signal.h>
X#include <curses.h>
X#include "karel.h"
X#include "help.h"
X
X#define scrnchr(t, s) (stdscr->_y[t][s] & 0177)
X
Xint cx, cy; /* cursor coordinates */
Xint x, y; /* Karel's x, y coord's */
Xint dir; /* Karel's heading */
X /* 0 = north */
X /* 1 = east */
X /* 2 = south */
X /* 3 = west */
Xint beepers; /* no. of beepers held */
Xint placed; /* 1 if Karel is placed */
Xint clearln; /* 1 if bottom line */
X /* should be cleared */
Xchar oldch; /* Karel is on top of */
Xchar scrnname[80]; /* name of screen */
XWINDOW *helpscrn; /* editor help screen */
XWINDOW *begscrn; /* screen at start */
X
Xeditscr() /* main interactive loop */
X{
X int c; /* keyboard input char */
X int newx, newy; /* coord's to move to */
X int done; /* signal to quit */
X
X done = 0;
X clearln = 0;
X c = getch();
X while (c != EOF && c != '\004' && !done) {
X if (c == ERR)
X screrror("getting character");
X /* clear bottom line if necessary */
X if (clearln)
X clearline();
X /* get current location */
X getyx(stdscr, cy, cx);
X newx = cx;
X newy = cy;
X switch (c) {
X case 'i':
X newy--;
X break;
X case 'j':
X newx--;
X break;
X case 'k':
X newx++;
X break;
X case 'm':
X newy++;
X break;
X case 'I':
X dir = 0;
X placekarel(cy, cx);
X break;
X case 'J':
X dir = 3;
X placekarel(cy, cx);
X break;
X case 'K':
X dir = 1;
X placekarel(cy, cx);
X break;
X case 'M':
X dir = 2;
X placekarel(cy, cx);
X break;
X case 'O':
X case 'o':
X placeobj('O');
X break;
X case 'Q':
X case 'q':
X done = 1;
X break;
X case '\r':
X case '\n':
X startprog();
X break;
X case 'S':
X snapshot();
X break;
X case 's':
X savescrn();
X break;
X case '8':
X case ':':
X case '*':
X putbeeper();
X break;
X case ' ':
X placeobj(' ');
X break;
X case '\014': /* control-L */
X redraw();
X break;
X case '?':
X case '/':
X help();
X break;
X }
X /* check to see if cursor moved off screen */
X if (newx>=1 && newx<COLS && newy>=0 && newy < LINES-2) {
X cy = newy;
X cx = newx;
X move(cy, cx);
X }
X update();
X if (!done)
X c = getch();
X }
X finish();
X}
X
Xinitialize() /* prepare for screen editing */
X{
X int k;
X
X if (initscr() == ERR || strcmp(ttytype, "unknown") == 0) {
X fprintf(stderr, "TERM variable not set\n");
X exit(0);
X }
X sprintf(scrnname, "%s.%s", basename, SCRSUFFIX);
X signal(SIGINT, interupt);
X scrollok(stdscr, FALSE);
X crmode();
X noecho();
X clear();
X /* set up help screen */
X helpscrn = newwin(0, 0, 0, 0);
X wclear(helpscrn);
X wmove(helpscrn, 0, 0);
X for (k = 0; helpmsg[k]; k++) {
X wprintw(helpscrn, helpmsg[k]);
X waddch(helpscrn, '\n');
X }
X wprintw(helpscrn, "\npress any key to continue: ");
X /* make a second screen to save beginning screen for execution */
X begscrn = newwin(0, 0, 0, 0);
X /* draw the boundaries */
X for (k = 0; k < LINES - 2; k++)
X mvaddch(k, 0, '|');
X mvaddch(LINES - 2, 0, '+');
X for (k = 1; k < COLS; k++)
X mvaddch(LINES - 2, k, '-');
X /* place the cursor in the center of the screen */
X cx = COLS / 2;
X cy = LINES / 2;
X placed = 0;
X oldch = ' ';
X move(cy, cx);
X redraw();
X}
X
Xreset() /* reset the screen to normal mode */
X{
X echo();
X nocrmode();
X endwin();
X}
X
Xredraw() /* redraw the screen */
X{
X /* force curses to redraw screen by copying screen, then copying back*/
X cpscrn(stdscr, begscrn);
X clear();
X cpscrn(begscrn, stdscr);
X touchwin(stdscr); /* make sure everything is drawn */
X move(cy, cx);
X update();
X}
X
Xupdate() /* refresh the screen */
X{
X if (refresh() == ERR)
X screrror("refreshing screen");
X}
X
Xplaceobj(c) /* place a wall, beeper, or space */
Xchar c;
X{
X if (cy == y && cx == x)
X placed = 0;
X addch(c);
X}
X
Xplacekarel(newy, newx) /* put karel on screen at new location */
Xint newy, newx;
X{
X char c; /* symbol karel will be shown as */
X
X if (placed)
X mvaddch(y, x, oldch);
X else
X placed = 1;
X move(newy, newx);
X oldch = inch();
X switch (dir) {
X case 0:
X c = '^';
X break;
X case 1:
X c = '>';
X break;
X case 2:
X c = 'v';
X break;
X case 3:
X c = '<';
X break;
X default:
X screrror("weird direction");
X }
X addch(c);
X y = newy;
X x = newx;
X}
X
Xputbeeper() /* put down one beeper */
X{
X char c; /* char that cursor is on top of */
X
X if (state == RUN)
X c = oldch;
X else
X c = inch();
X if (c == '*')
X c = '2';
X else {
X if (c >= '0' && c <= '8')
X c++;
X else {
X if (c != '9')
X c = '*';
X else {
X shutoff("stacked beepers too high");
X return;
X }
X }
X }
X if (state == RUN) {
X if (--beepers < 0)
X shutoff("don't have enough beepers");
X else
X oldch = c;
X }
X else
X placeobj(c);
X}
X
Xhelp() /* print editor help screen */
X{
X touchwin(helpscrn);
X if (wrefresh(helpscrn) == ERR)
X screrror("refreshing help screen");
X if (wgetch(helpscrn) == ERR)
X screrror("getting character");
X redraw();
X}
X
Xsavescrn() /* save the screen to a file */
X{
X int k, j; /* loop indexes */
X FILE *fp; /* output file */
X FILE *fopen();
X
X if ((fp = fopen(scrnname, "w")) == NULL)
X syserr("can't open file: ", scrnname);
X for (k = 0; k < LINES - 2; k++) {
X for (j = 1; j < COLS; j++)
X fputc(scrnchr(k, j), fp);
X fputc('\n', fp);
X }
X fclose(fp);
X prbotln("screen saved");
X clearln = 1;
X move(cy, cx);
X}
X
Xsnapshot() /* save screen with the borders */
X{
X int k, j; /* loop indexes */
X FILE *fp; /* output file */
X FILE *fopen();
X
X if ((fp = fopen("snapshot", "w")) == NULL)
X syserr("can't open file: snapshot");
X for (k = 0; k < LINES - 2; k++) {
X fputc('|', fp);
X for (j = 1; j < COLS; j++)
X fputc(scrnchr(k, j), fp);
X fputc('\n', fp);
X }
X fputc('+', fp);
X for (k = 1; k < COLS; k++)
X fputc('-', fp);
X fputc('\n', fp);
X fclose(fp);
X prbotln("snapshot saved");
X clearln = 1;
X move(cy, cx);
X}
X
Xsideclear(n) /* return 1 if side n is clear, 0 otherwise */
Xint n;
X{
X int retval; /* value to be returned */
X
X retval = 1;
X /* make sure side-number is between 0 and 3 */
X while (n < 0)
X n += 4;
X n = n % 4;
X switch (n) {
X case 0:
X if (y == 0)
X retval = 0;
X else
X if (scrnchr(y - 1, x) == 'O')
X retval = 0;
X break;
X case 1:
X if (x == COLS - 1)
X retval = 0;
X else
X if (scrnchr(y, x + 1) == 'O')
X retval = 0;
X break;
X case 2:
X if (y == LINES - 3)
X retval = 0;
X else
X if (scrnchr(y + 1, x) == 'O')
X retval = 0;
X break;
X case 3:
X if (x == 1)
X retval = 0;
X else
X if (scrnchr(y, x - 1) == 'O')
X retval = 0;
X break;
X }
X return(retval);
X}
X
Xmovekarel() /* move karel one character forward */
X{
X int newx, newy;
X
X newx = x;
X newy = y;
X if (sideclear(dir)) {
X switch (dir) {
X case 0:
X newy--;
X break;
X case 1:
X newx++;
X break;
X case 2:
X newy++;
X break;
X case 3:
X newx--;
X break;
X }
X placekarel(newy, newx);
X cy = newy;
X cx = newx;
X }
X else
X shutoff("hit a wall");
X}
X
Xfinish() /* clean up; reset terminal modes, etc. */
X{
X scrollok(stdscr, TRUE);
X if (move(LINES - 1, 0) == ERR)
X screrror("moving to bottom of screen");
X if (clrtoeol() == ERR)
X screrror("clearing bottom line");
X if (refresh() == ERR)
X screrror("refreshing screen");
X reset();
X}
X
Xpickbeeper() /* pick up one beeper underneath karel */
X{
X if (oldch == ' ')
X shutoff("tried to pick non-existent beeper");
X else {
X if (oldch == '*')
X oldch = ' ';
X else
X if (oldch == '0')
X oldch = '*';
X else
X oldch--;
X beepers++;
X }
X}
X
Xreadscrn() /* read screen in from a file */
X{
X int k, j; /* loop indexes */
X FILE *fp; /* screen file */
X FILE *fopen();
X char c; /* char being read */
X char *kar; /* these two used to */
X char *kars = "^>v<"; /* place karel */
X char *index();
X
X if ((fp = fopen(scrnname, "r")) != NULL) {
X for (k = 0; k < LINES - 2; k++) {
X for (j = 1; j < COLS; j++) {
X if ((c = getc(fp)) == EOF)
X break;
X if (c != ' ') {
X if (kar = index(kars, c)) {
X dir = 4 - strlen(kar);
X placekarel(k, j);
X }
X else
X mvaddch(k, j, c);
X }
X }
X getc(fp); /* ignore newline */
X }
X fclose(fp);
X }
X move(cy, cx);
X update();
X}
X
Xshutoff(s) /* print s on bottom of screen */
Xchar *s;
X{
X char mesg[BUFSIZ];
X
X state = OFF;
X sprintf(mesg, "\007error shutoff: %.45s. press any key: ", s);
X prbotln(mesg);
X update();
X if (getch() == ERR)
X screrror("getting character");
X if (move(cy, cx) == ERR)
X screrror("moving cursor to karel");
X clearln = 1;
X}
X
Xclearline() /* clear bottom line of screen */
X{
X mvbot();
X if (clrtoeol() == ERR)
X screrror("clearing bottom line");
X if (move(cy, cx) == ERR)
X screrror("moving cursor to karel");
X clearln = 0;
X}
X
Xstartprog() /* prepare for execution, then call program */
X{
X int begx, begy; /* these are all temporary */
X int begdir; /* variables to save conditions */
X int begoldch; /* at start of execution */
X int begbeepers;
X int c; /* key user presses */
X
X /* save current status */
X begx = x;
X begy = y;
X begdir = dir;
X begoldch = oldch;
X begbeepers = beepers;
X cpscrn(stdscr, begscrn);
X if (!placed)
X shutoff("karel has not been placed");
X else {
X state = RUN;
X execute(startaddr);
X if (state != OFF)
X shutoff("turnoff instruction never reached");
X if (clearln == 0) {
X mvbot();
X printw("press any key: ");
X update();
X if ((c = getch()) == ERR)
X screrror("getting character");
X }
X else
X clearln = 0;
X clearline();
X /* restore previous status if ESC was not pressed */
X if (c != '\033') {
X x = begx;
X y = begy;
X dir = begdir;
X oldch = begoldch;
X beepers = begbeepers;
X cpscrn(begscrn, stdscr);
X }
X update();
X }
X state = EDIT;
X}
X
Xcpscrn(a, b) /* copy screen a to screen b */
XWINDOW *a, *b;
X{
X int k, j; /* loop indexes */
X
X for (k = 0; k < LINES - 1; k++)
X for (j = 0; j < COLS; j++)
X b->_y[k][j] = a->_y[k][j];
X touchwin(b);
X}
X
Xmvbot() /* move to bottom of screen */
X{
X if (move(LINES - 1, 0) == ERR)
X screrror("moving cursor to bottom of screen");
X}
X
Xprbotln(s) /* print a line on the bottom of screen */
Xchar *s;
X{
X mvbot();
X if (clrtoeol() == ERR)
X screrror("clearing bottom line");
X printw("%s", s);
X update();
X}
!SHAR!EOF!
echo x - symbol.c
sed 's/^X//' > symbol.c << !SHAR!EOF!
X#include "karel.h"
X
Xstatic Symbol *symtab = 0; /* the symbol table */
X
XSymbol *lookup(s) /* find s in symbol table */
Xchar *s;
X{
X Symbol *sp; /* loop index */
X
X for (sp = symtab; sp != (Symbol *) 0; sp = sp->next)
X if (strcmp(s, sp->name) == 0)
X return(sp);
X return(0); /* not found */
X}
X
Xinstall(s) /* install s in symbol table */
Xchar *s;
X{
X char *emalloc();
X Symbol *sp; /* new symbol table entry */
X
X sp = (Symbol *) emalloc(sizeof(Symbol));
X sp->name = emalloc(strlen(s) + 1);
X strcpy(sp->name, s);
X sp->addr = progp;
X sp->next = symtab;
X symtab = sp;
X}
X
Xchar *emalloc(n) /* do malloc with error checking */
Xint n;
X{
X char *p; /* pointer to free memory */
X char *malloc();
X
X if ((p = malloc(n)) == (char *) 0)
X syserr("out of memory", (char *) 0);
X return(p);
X}
!SHAR!EOF!
echo x - words.h
sed 's/^X//' > words.h << !SHAR!EOF!
X#include "y.tab.h"
X
X/* these lists must be sorted alphabetically in order for the */
X/* binary search routine to work */
X
X
X/* keywords */
X
Xstruct {
X char *name;
X int keyid;
X} keywords[] = {
X "AS", AS,
X "BEGIN", BEGIN,
X "BEGINNING-OF-EXECUTION", BEGEXEC,
X "BEGINNING-OF-PROGRAM", BEGPROG,
X "DEFINE-NEW-INSTRUCTION", DEFINST,
X "DO", DO,
X "ELSE", ELSE,
X "END", END,
X "END-OF-EXECUTION", ENDEXEC,
X "END-OF-PROGRAM", ENDPROG,
X "IF", IF,
X "ITERATE", ITERATE,
X "THEN", THEN,
X "TIMES", TIMES,
X "WHILE", WHILE,
X 0, 0
X};
X
X
X/* built-in procedures and tests */
X
XBltintype bltins[] = {
X "any-beepers-in-beeper-bag", anybeepers, TEST,
X "facing-east", facingeast, TEST,
X "facing-north", facingnorth, TEST,
X "facing-south", facingsouth, TEST,
X "facing-west", facingwest, TEST,
X "front-is-blocked", frontblocked, TEST,
X "front-is-clear", frontclear, TEST,
X "left-is-blocked", leftblocked, TEST,
X "left-is-clear", leftclear, TEST,
X "move", movekarel, BLTIN,
X "next-to-a-beeper", nexttobeeper, TEST,
X "no-beepers-in-beeper-bag", nobeepers, TEST,
X "not-facing-east", notfacingeast, TEST,
X "not-facing-north", notfacingnorth, TEST,
X "not-facing-south", notfacingsouth, TEST,
X "not-facing-west", notfacingwest, TEST,
X "not-next-to-a-beeper", notnexttobeeper, TEST,
X "pickbeeper", pickbeeper, BLTIN,
X "putbeeper", putbeeper, BLTIN,
X "right-is-blocked", rightblocked, TEST,
X "right-is-clear", rightclear, TEST,
X "turnleft", turnleft, BLTIN,
X "turnoff", turnoff, BLTIN,
X 0, 0, 0
X};
!SHAR!EOF!
echo x - maze.k
sed 's/^X//' > maze.k << !SHAR!EOF!
X
X{ karel maze demo: robot will follow the right wall until he finds a beeper }
X
XBEGINNING-OF-PROGRAM
X DEFINE-NEW-INSTRUCTION turnright AS
X ITERATE 3 TIMES
X turnleft;
X
X BEGINNING-OF-EXECUTION
X WHILE not-next-to-a-beeper DO
X BEGIN
X IF right-is-clear
X THEN turnright
X ELSE
X WHILE front-is-blocked DO
X turnleft;
X move
X END;
X turnoff
X END-OF-EXECUTION
X
XEND-OF-PROGRAM
!SHAR!EOF!
echo x - maze.scr
sed 's/^X//' > maze.scr << !SHAR!EOF!
X
X
X
X
X
X
X
X
X
X
XOOOOOOOOOOOOOOOOOOOOOOO
X O O O O
X OOOOOO O OOOOO OOO O O
X O O O O O
XOOO OOOOOOO O OOO O *
X OOOOOOO O O O
X OOOOOOOO O O O OOO
X O O O OOO O O
X OOO OOOOOOOO O O O O
X O OOO O O O
X O OOOOOO O OOO O OOO O
X^O O O O
!SHAR!EOF!
More information about the Comp.sources.unix
mailing list