Let's try this. It's BUGGERED.

This commit is contained in:
rsc 2004-05-15 23:24:00 +00:00
parent 76e6aca867
commit 5cedca1b69
118 changed files with 26947 additions and 1 deletions

71
src/cmd/grap/coord.c Normal file
View file

@ -0,0 +1,71 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "grap.h"
#include "y.tab.h"
char *dflt_coord = "gg";
char *curr_coord = "gg";
int ncoord = 0; /* number of explicit coord's given */
Point xcoord;
Point ycoord;
int xcflag = 0; /* 1 if xcoord set */
int ycflag = 0;
int logcoord = 0;
void coord_x(Point pt) /* remember x coord */
{
xcoord = pt;
xcflag = 1;
margin = 0; /* no extra space around picture if explicit coords */
}
void coord_y(Point pt)
{
ycoord = pt;
ycflag = 1;
margin = 0; /* no extra space if explicit coords */
}
void coordlog(int n) /* remember log scaling */
{
logcoord = n;
}
void coord(Obj *p) /* set coord range */
{
static char buf[10];
ncoord++;
if (ncoord > 1 && strcmp(p->name, dflt_coord) == 0) {
/* resetting default coordinate by implication */
sprintf(buf, "gg%d", ncoord);
dflt_coord = buf;
p = lookup(dflt_coord, 1);
}
if (xcflag) {
p->coord |= XFLAG;
p->pt.x = min(xcoord.x,xcoord.y); /* "xcoord" is xmin, xmax */
p->pt1.x = max(xcoord.x,xcoord.y);
if ((logcoord&XFLAG) && p->pt.x <= 0.0)
ERROR "can't have log of x coord %g,%g", p->pt.x, p->pt1.x FATAL;
xcflag = 0;
}
if (ycflag) {
p->coord |= YFLAG;
p->pt.y = min(ycoord.x,ycoord.y); /* "ycoord" is ymin, ymax */
p->pt1.y = max(ycoord.x,ycoord.y);
if ((logcoord&YFLAG) && p->pt.y <= 0.0)
ERROR "can't have log of y coord %g,%g", p->pt.y, p->pt1.y FATAL;
ycflag = 0;
}
p->log = logcoord;
logcoord = 0;
auto_x = 0;
}
void resetcoord(Obj *p) /* reset current coordinate */
{
curr_coord = p->name;
}

1
src/cmd/grap/find Normal file
View file

@ -0,0 +1 @@
exec /usr/bin/egrep -n "$1" *.[chyl]

89
src/cmd/grap/for.c Normal file
View file

@ -0,0 +1,89 @@
#include <stdio.h>
#include <stdlib.h>
#include "grap.h"
#include "y.tab.h"
typedef struct {
Obj *var; /* index variable */
double to; /* limit */
double by;
int op; /* operator */
char *str; /* string to push back */
} For;
#define MAXFOR 10
For forstk[MAXFOR]; /* stack of for loops */
For *forp = forstk; /* pointer to current top */
void forloop(Obj *var, double from, double to, int op, double by, char *str) /* set up a for loop */
{
fprintf(tfd, "# for %s from %g to %g by %c %g \n",
var->name, from, to, op, by);
if (++forp >= forstk+MAXFOR)
ERROR "for loop nested too deep" FATAL;
forp->var = var;
forp->to = to;
forp->op = op;
forp->by = by;
forp->str = str;
setvar(var, from);
nextfor();
unput('\n');
}
void nextfor(void) /* do one iteration of a for loop */
{
/* BUG: this should depend on op and direction */
if (forp->var->fval > SLOP * forp->to) { /* loop is done */
free(forp->str);
if (--forp < forstk)
ERROR "forstk popped too far" FATAL;
} else { /* another iteration */
pushsrc(String, "\nEndfor\n");
pushsrc(String, forp->str);
}
}
void endfor(void) /* end one iteration of for loop */
{
switch (forp->op) {
case '+':
case ' ':
forp->var->fval += forp->by;
break;
case '-':
forp->var->fval -= forp->by;
break;
case '*':
forp->var->fval *= forp->by;
break;
case '/':
forp->var->fval /= forp->by;
break;
}
nextfor();
}
char *ifstat(double expr, char *thenpart, char *elsepart)
{
dprintf("if %g then <%s> else <%s>\n", expr, thenpart, elsepart? elsepart : "");
if (expr) {
unput('\n');
pushsrc(Free, thenpart);
pushsrc(String, thenpart);
unput('\n');
if (elsepart)
free(elsepart);
return thenpart; /* to be freed later */
} else {
free(thenpart);
if (elsepart) {
unput('\n');
pushsrc(Free, elsepart);
pushsrc(String, elsepart);
unput('\n');
}
return elsepart;
}
}

71
src/cmd/grap/frame.c Normal file
View file

@ -0,0 +1,71 @@
#include <stdio.h>
#include <stdlib.h>
#include "grap.h"
#include "y.tab.h"
double frame_ht; /* default frame height */
double frame_wid; /* and width */
int nsides = 0; /* how many sides given on this frame */
char *sides[] = {
"\tline from Frame.nw to Frame.ne",
"\tline from Frame.sw to Frame.se",
"\tline from Frame.sw to Frame.nw",
"\tline from Frame.se to Frame.ne"
};
char *newsides[4] = { 0, 0, 0, 0 }; /* filled in later */
void frame(void) /* pump out frame definition, reset for next */
{
int i;
fprintf(tfd, "\tframeht = %g\n", frame_ht);
fprintf(tfd, "\tframewid = %g\n", frame_wid);
fprintf(tfd, "Frame:\tbox ht frameht wid framewid with .sw at 0,0 ");
if (nsides == 0)
fprintf(tfd, "\n");
else {
fprintf(tfd, "invis\n");
for (i = 0; i < 4; i++) {
if (newsides[i]) {
fprintf(tfd, "%s\n", newsides[i]);
free(newsides[i]);
newsides[i] = 0;
} else
fprintf(tfd, "%s\n", sides[i]);
}
nsides = 0;
}
}
void frameht(double f) /* set height of frame */
{
frame_ht = f;
}
void framewid(double f) /* set width of frame */
{
frame_wid = f;
}
void frameside(int type, Attr *desc) /* create and remember sides */
{
int n;
char buf[100];
nsides++;
switch (type) {
case 0: /* no side specified; kludge up all */
frameside(TOP, desc);
frameside(BOT, desc);
frameside(LEFT, desc);
frameside(RIGHT, desc);
return;
case TOP: n = 0; break;
case BOT: n = 1; break;
case LEFT: n = 2; break;
case RIGHT: n = 3; break;
}
sprintf(buf, "%s %s", sides[n], desc_str(desc));
newsides[n] = tostring(buf);
}

236
src/cmd/grap/grap.h Normal file
View file

@ -0,0 +1,236 @@
extern char errbuf[200];
#define ERROR sprintf(errbuf,
#define FATAL ), yyerror(errbuf), exit(1)
#define WARNING ), yyerror(errbuf)
#define dprintf if(dbg)printf
#define String 01
#define Macro 02
#define File 04
#define Char 010
#define Thru 020
#define Free 040
#define MARGIN 0.07 /* default margin around data */
#define SLOP 1.001 /* slop for limits of for loops */
#define FRAMEWID 3 /* default width for boxes and ellipses */
#define FRAMEHT 2 /* default height and line length */
#define TICKLEN 0.1
#define MAXNUM 200
#define XFLAG 01
#define YFLAG 02
#define INTICK 01
#define OUTICK 02
#define BOT 01
#define TOP 02
#define RIGHT 04
#define LEFT 010
#define RJUST 01
#define LJUST 02
#define ABOVE 04
#define BELOW 010
typedef struct infile {
FILE *fin;
char *fname;
int lineno;
} Infile;
typedef struct { /* input source */
int type; /* Macro, String, File */
char *sp; /* if String or Macro */
} Src;
extern Src src[], *srcp; /* input source stack */
#define MAXARGS 100
typedef struct { /* argument stack */
char *argstk[MAXARGS]; /* pointers to args */
char *argval; /* points to space containing args */
} Arg;
extern Infile infile[10];
extern Infile *curfile;
typedef struct {
struct obj *obj;
double x, y;
} Point;
typedef struct attr { /* e.g., DASH 1.1 or "..." rjust size *.5 */
int type;
double fval;
char *sval;
int just; /* justification, for STRING type */
int op; /* optional operator, ditto */
struct attr *next;
} Attr;
typedef struct obj { /* a name and its properties */
char *name;
char *val; /* body of define, etc. */
double fval; /* if a numeric variable */
Point pt; /* usually for max and min */
Point pt1;
int type; /* NAME, DEFNAME, ... */
int first; /* 1 after 1st item seen */
int coord; /* 1 if coord system specified for this name */
int log; /* x, y, or z (= x+y) */
Attr *attr; /* DASH, etc., for now */
struct obj *next;
} Obj;
typedef union { /* the yacc stack type */
int i;
char *p;
double f;
Point pt;
Obj *op;
Attr *ap;
} YYSTYPE;
extern YYSTYPE yylval, yyval;
extern int dbg;
extern int ntext;
extern double num[MAXNUM];
extern int nnum;
extern int ntick, tside;
extern char *tostring(char *);
extern char *grow(char *, char *, int, int);
extern int lineno;
extern int synerr;
extern int codegen;
extern char tempfile[];
extern FILE *tfd;
extern Point ptmin, ptmax;
extern char *dflt_coord;
extern char *curr_coord;
extern int ncoord;
extern int auto_x;
extern double margin;
extern int autoticks;
extern int pointsize, ps_set;
#define logit(x) (x) = log10(x)
#define Log10(x) errcheck(log10(x), "log")
#define Exp(x) errcheck(exp(x), "exp")
#define Sqrt(x) errcheck(sqrt(x), "sqrt")
#define min(x,y) (((x) <= (y)) ? (x) : (y))
#define max(x,y) (((x) >= (y)) ? (x) : (y))
extern void yyerror(char *);
extern void coord_x(Point);
extern void coord_y(Point);
extern void coordlog(int);
extern void coord(Obj *);
extern void resetcoord(Obj *);
extern void savenum(int, double);
extern void setjust(int);
extern void setsize(int, double);
extern void range(Point);
extern void halfrange(Obj *, int, double);
extern Obj *lookup(char *, int);
extern double getvar(Obj *);
extern double setvar(Obj *, double);
extern Point makepoint(Obj *, double, double);
extern Attr *makefattr(int, double);
extern Attr *makesattr(char *);
extern Attr *makeattr(int, double, char *, int, int);
extern Attr *addattr(Attr *, Attr *);
extern void freeattr(Attr *);
extern char *slprint(Attr *);
extern char *juststr(int);
extern char *sprntf(char *, Attr *);
extern void forloop(Obj *, double, double, int, double, char *);
extern void nextfor(void);
extern void endfor(void);
extern char *ifstat(double, char *, char *);
extern void frame(void);
extern void frameht(double);
extern void framewid(double);
extern void frameside(int, Attr *);
extern void pushsrc(int, char *);
extern void popsrc(void);
extern void definition(char *);
extern char *delimstr(char *);
extern int baldelim(int, char *);
extern void dodef(Obj *);
extern int getarg(char *);
extern int input(void);
extern int nextchar(void);
extern void do_thru(void);
extern int unput(int);
extern void pbstr(char *);
extern double errcheck(double, char *);
extern void yyerror(char *);
extern void eprint(void);
extern int yywrap(void);
extern void copyfile(char *);
extern void copydef(Obj *);
extern Obj *copythru(char *);
extern char *addnewline(char *);
extern void copyuntil(char *);
extern void copy(void);
extern void shell_init(void);
extern void shell_text(char *);
extern void shell_exec(void);
extern void labelwid(double);
extern void labelmove(int, double);
extern void label(int, Attr *);
extern void lab_adjust(void);
extern char *sizeit(Attr *);
extern void line(int, Point, Point, Attr *);
extern void circle(double, Point);
extern char *xyname(Point);
extern void pic(char *);
extern void numlist(void);
extern void plot(Attr *, Point);
extern void plotnum(double, char *, Point);
extern void drawdesc(int, Obj *, Attr *, char *);
extern void next(Obj *, Point, Attr *);
extern void print(void);
extern void endstat(void);
extern void graph(char *);
extern void setup(void);
extern void do_first(void);
extern void reset(void);
extern void opentemp(void);
extern void savetick(double, char *);
extern void dflt_tick(double);
extern void tickside(int);
extern void tickoff(int);
extern void gridtickoff(void);
extern void setlist(void);
extern void tickdir(int, double, int);
extern void ticks(void);
extern double modfloor(double, double);
extern double modceil(double, double);
extern void do_autoticks(Obj *);
extern void logtick(double, double, double);
extern Obj *setauto(void);
extern void autoside(Obj *, int);
extern void autolog(Obj *, int);
extern void iterator(double, double, int, double, char *);
extern void ticklist(Obj *, int);
extern void print_ticks(int, int, Obj *, char *, char *);
extern void maketick(int, char *, int, int, double, char *, char *, char *);
extern void griddesc(Attr *);
extern void gridlist(Obj *);
extern char *desc_str(Attr *);
extern int sidelog(int, int);
extern Obj *objlist;

396
src/cmd/grap/grap.y Normal file
View file

@ -0,0 +1,396 @@
%{
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "grap.h"
//#define RAND_MAX 32767 /* if your rand() returns bigger, change this too */
extern int yylex(void);
extern int yyparse(void);
%}
%token <i> FRAME TICKS GRID LABEL COORD
%token <i> LINE ARROW CIRCLE DRAW NEW PLOT NEXT
%token <p> PIC
%token <i> COPY THRU UNTIL
%token <i> FOR FROM TO BY AT WITH
%token <i> IF
%token <p> GRAPH THEN ELSE DOSTR
%token <i> DOT DASH INVIS SOLID
%token <i> TEXT JUST SIZE
%token <i> LOG EXP SIN COS ATAN2 SQRT RAND MAX MIN INT PRINT SPRINTF
%token <i> X Y SIDE IN OUT OFF UP DOWN ACROSS
%token <i> HEIGHT WIDTH RADIUS
%token <f> NUMBER
%token <op> NAME VARNAME DEFNAME
%token <p> STRING
%token <i> ST '(' ')' ','
%right <f> '='
%left <f> OR
%left <f> AND
%nonassoc <f> GT LT LE GE EQ NE
%left <f> '+' '-'
%left <f> '*' '/' '%'
%right <f> UMINUS NOT
%right <f> '^'
%type <f> expr optexpr if_expr number assign
%type <i> optop
%type <p> optstring if
%type <op> optname iterator name
%type <pt> point
%type <i> side optside numlist comma linetype drawtype
%type <ap> linedesc optdesc stringlist string stringattr sattrlist exprlist
%type <i> frameitem framelist coordlog
%type <f> string_expr
%%
top:
graphseq { if (codegen && !synerr) graph((char *) 0); }
| /* empty */ { codegen = 0; }
| error { codegen = 0; ERROR "syntax error" WARNING; }
;
graphseq:
statlist
| graph statlist
| graphseq graph statlist
;
graph:
GRAPH { graph($1); endstat(); }
;
statlist:
ST
| stat ST { endstat(); }
| statlist stat ST { endstat(); }
;
stat:
FRAME framelist { codegen = 1; }
| ticks { codegen = 1; }
| grid { codegen = 1; }
| label { codegen = 1; }
| coord
| plot { codegen = 1; }
| line { codegen = 1; }
| circle { codegen = 1; }
| draw
| next { codegen = 1; }
| PIC { codegen = 1; pic($1); }
| for
| if
| copy
| numlist { codegen = 1; numlist(); }
| assign
| PRINT expr { fprintf(stderr, "\t%g\n", $2); }
| PRINT string { fprintf(stderr, "\t%s\n", $2->sval); freeattr($2); }
| /* empty */
;
numlist:
number { savenum(0, $1); $$ = 1; }
| numlist number { savenum($1, $2); $$ = $1+1; }
| numlist comma number { savenum($1, $3); $$ = $1+1; }
;
number:
NUMBER
| '-' NUMBER %prec UMINUS { $$ = -$2; }
| '+' NUMBER %prec UMINUS { $$ = $2; }
;
label:
LABEL optside stringlist lablist { label($2, $3); }
;
lablist:
labattr
| lablist labattr
| /* empty */
;
labattr:
UP expr { labelmove($1, $2); }
| DOWN expr { labelmove($1, $2); }
| SIDE expr { labelmove($1, $2); /* LEFT or RIGHT only */ }
| WIDTH expr { labelwid($2); }
;
framelist:
framelist frameitem
| /* empty */ { $$ = 0; }
;
frameitem:
HEIGHT expr { frameht($2); }
| WIDTH expr { framewid($2); }
| side linedesc { frameside($1, $2); }
| linedesc { frameside(0, $1); }
;
side:
SIDE
;
optside:
side
| /* empty */ { $$ = 0; }
;
linedesc:
linetype optexpr { $$ = makeattr($1, $2, (char *) 0, 0, 0); }
;
linetype:
DOT | DASH | SOLID | INVIS
;
optdesc:
linedesc
| /* empty */ { $$ = makeattr(0, 0.0, (char *) 0, 0, 0); }
;
ticks:
TICKS tickdesc { ticks(); }
;
tickdesc:
tickattr
| tickdesc tickattr
;
tickattr:
side { tickside($1); }
| IN expr { tickdir(IN, $2, 1); }
| OUT expr { tickdir(OUT, $2, 1); }
| IN { tickdir(IN, 0.0, 0); }
| OUT { tickdir(OUT, 0.0, 0); }
| AT optname ticklist { setlist(); ticklist($2, AT); }
| iterator { setlist(); ticklist($1, AT); }
| side OFF { tickoff($1); }
| OFF { tickoff(LEFT|RIGHT|TOP|BOT); }
| labattr
;
ticklist:
tickpoint
| ticklist comma tickpoint
;
tickpoint:
expr { savetick($1, (char *) 0); }
| expr string { savetick($1, $2->sval); }
;
iterator:
FROM optname expr TO optname expr BY optop expr optstring
{ iterator($3, $6, $8, $9, $10); $$ = $2; }
| FROM optname expr TO optname expr optstring
{ iterator($3, $6, '+', 1.0, $7); $$ = $2; }
;
optop:
'+' { $$ = '+'; }
| '-' { $$ = '-'; }
| '*' { $$ = '*'; }
| '/' { $$ = '/'; }
| /* empty */ { $$ = ' '; }
;
optstring:
string { $$ = $1->sval; }
| /* empty */ { $$ = (char *) 0; }
;
grid:
GRID griddesc { ticks(); }
;
griddesc:
gridattr
| griddesc gridattr
;
gridattr:
side { tickside($1); }
| X { tickside(BOT); }
| Y { tickside(LEFT); }
| linedesc { griddesc($1); }
| AT optname ticklist { setlist(); gridlist($2); }
| iterator { setlist(); gridlist($1); }
| TICKS OFF { gridtickoff(); }
| OFF { gridtickoff(); }
| labattr
;
line:
LINE FROM point TO point optdesc { line($1, $3, $5, $6); }
| LINE optdesc FROM point TO point { line($1, $4, $6, $2); }
;
circle:
CIRCLE RADIUS expr AT point { circle($3, $5); }
| CIRCLE AT point RADIUS expr { circle($5, $3); }
| CIRCLE AT point { circle(0.0, $3); }
;
stringlist:
string
| stringlist string { $$ = addattr($1, $2); }
;
string:
STRING sattrlist { $$ = makesattr($1); }
| SPRINTF '(' STRING ')' sattrlist
{ $$ = makesattr(sprntf($3, (Attr*) 0)); }
| SPRINTF '(' STRING ',' exprlist ')' sattrlist
{ $$ = makesattr(sprntf($3, $5)); }
;
exprlist:
expr { $$ = makefattr(NUMBER, $1); }
| exprlist ',' expr { $$ = addattr($1, makefattr(NUMBER, $3)); }
;
sattrlist:
stringattr
| sattrlist stringattr
| /* empty */ { $$ = (Attr *) 0; }
;
stringattr:
JUST { setjust($1); }
| SIZE optop expr { setsize($2, $3); }
;
coord:
COORD optname coordlist { coord($2); }
| COORD optname { resetcoord($2); }
;
coordlist:
coorditem
| coordlist coorditem
;
coorditem:
coordlog { coordlog($1); }
| X point { coord_x($2); }
| Y point { coord_y($2); }
| X optname expr TO expr { coord_x(makepoint($2, $3, $5)); }
| Y optname expr TO expr { coord_y(makepoint($2, $3, $5)); }
| X FROM optname expr TO expr { coord_x(makepoint($3, $4, $6)); }
| Y FROM optname expr TO expr { coord_y(makepoint($3, $4, $6)); }
;
coordlog:
LOG X { $$ = XFLAG; }
| LOG Y { $$ = YFLAG; }
| LOG X LOG Y { $$ = XFLAG|YFLAG; }
| LOG Y LOG X { $$ = XFLAG|YFLAG; }
| LOG LOG { $$ = XFLAG|YFLAG; }
;
plot:
stringlist AT point { plot($1, $3); }
| PLOT stringlist AT point { plot($2, $4); }
| PLOT expr optstring AT point { plotnum($2, $3, $5); }
;
draw:
drawtype optname linedesc { drawdesc($1, $2, $3, (char *) 0); }
| drawtype optname optdesc string { drawdesc($1, $2, $3, $4->sval); }
| drawtype optname string optdesc { drawdesc($1, $2, $4, $3->sval); }
;
drawtype:
DRAW
| NEW
;
next:
NEXT optname AT point optdesc { next($2, $4, $5); }
copy:
COPY copylist { copy(); }
;
copylist:
copyattr
| copylist copyattr
;
copyattr:
string { copyfile($1->sval); }
| THRU DEFNAME { copydef($2); }
| UNTIL string { copyuntil($2->sval); }
;
for:
FOR name FROM expr TO expr BY optop expr DOSTR
{ forloop($2, $4, $6, $8, $9, $10); }
| FOR name FROM expr TO expr DOSTR
{ forloop($2, $4, $6, '+', 1.0, $7); }
| FOR name '=' expr TO expr BY optop expr DOSTR
{ forloop($2, $4, $6, $8, $9, $10); }
| FOR name '=' expr TO expr DOSTR
{ forloop($2, $4, $6, '+', 1.0, $7); }
;
if:
IF if_expr THEN ELSE { $$ = ifstat($2, $3, $4); }
| IF if_expr THEN { $$ = ifstat($2, $3, (char *) 0); }
;
if_expr:
expr
| string_expr
| if_expr AND string_expr { $$ = $1 && $3; }
| if_expr OR string_expr { $$ = $1 || $3; }
;
string_expr:
STRING EQ STRING { $$ = strcmp($1,$3) == 0; free($1); free($3); }
| STRING NE STRING { $$ = strcmp($1,$3) != 0; free($1); free($3); }
;
point:
optname expr comma expr { $$ = makepoint($1, $2, $4); }
| optname '(' expr comma expr ')' { $$ = makepoint($1, $3, $5); }
;
comma:
',' { $$ = ','; }
;
optname:
NAME { $$ = $1; }
| /* empty */ { $$ = lookup(curr_coord, 1); }
;
expr:
NUMBER
| assign
| '(' string_expr ')' { $$ = $2; }
| VARNAME { $$ = getvar($1); }
| expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr { if ($3 == 0.0) {
ERROR "division by 0" WARNING; $3 = 1; }
$$ = $1 / $3; }
| expr '%' expr { if ((long)$3 == 0) {
ERROR "mod division by 0" WARNING; $3 = 1; }
$$ = (long)$1 % (long)$3; }
| '-' expr %prec UMINUS { $$ = -$2; }
| '+' expr %prec UMINUS { $$ = $2; }
| '(' expr ')' { $$ = $2; }
| LOG '(' expr ')' { $$ = Log10($3); }
| EXP '(' expr ')' { $$ = Exp($3 * log(10.0)); }
| expr '^' expr { $$ = pow($1, $3); }
| SIN '(' expr ')' { $$ = sin($3); }
| COS '(' expr ')' { $$ = cos($3); }
| ATAN2 '(' expr ',' expr ')' { $$ = atan2($3, $5); }
| SQRT '(' expr ')' { $$ = Sqrt($3); }
| RAND '(' ')' { $$ = (double)rand() / (double)RAND_MAX; }
| MAX '(' expr ',' expr ')' { $$ = $3 >= $5 ? $3 : $5; }
| MIN '(' expr ',' expr ')' { $$ = $3 <= $5 ? $3 : $5; }
| INT '(' expr ')' { $$ = (long) $3; }
| expr GT expr { $$ = $1 > $3; }
| expr LT expr { $$ = $1 < $3; }
| expr LE expr { $$ = $1 <= $3; }
| expr GE expr { $$ = $1 >= $3; }
| expr EQ expr { $$ = $1 == $3; }
| expr NE expr { $$ = $1 != $3; }
| expr AND expr { $$ = $1 && $3; }
| expr OR expr { $$ = $1 || $3; }
| NOT expr { $$ = !($2); }
;
assign:
name '=' expr { $$ = setvar($1, $3); }
;
name:
NAME
| VARNAME
;
optexpr:
expr
| /* empty */ { $$ = 0.0; }
;

213
src/cmd/grap/grapl.lx Normal file
View file

@ -0,0 +1,213 @@
%Start A str def thru sh
%{
#undef input
#undef unput
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "grap.h"
#include "y.tab.h"
extern struct symtab symtab[];
int yyback(int *, int);
int yylook(void);
int yywrap(void);
void shell_init(void), shell_exec(void), shell_text(char *);
#define CADD cbuf[clen++] = yytext[0]; \
if (clen >= CBUFLEN-1) { \
ERROR "string too long", cbuf WARNING; BEGIN A; }
#define CBUFLEN 1500
char cbuf[CBUFLEN];
int clen, cflag;
int c, delim, shcnt;
%}
A [a-zA-Z_]
B [a-zA-Z0-9_]
D [0-9]
WS [ \t]
%%
if (yybgin-yysvec-1 == 0) { /* witchcraft */
BEGIN A;
}
<A>{WS} ;
<A>"\\"\n ;
<A>\n return(ST);
<A>";" return(ST);
<A>line return(yylval.i = LINE);
<A>arrow { yylval.i = ARROW; return(LINE); }
<A>circle return(yylval.i = CIRCLE);
<A>frame return(FRAME);
<A>tick(s)? return(TICKS);
<A>grid(line)?(s)? return(GRID);
<A>coord(s)? return(COORD);
<A>log return(LOG);
<A>exp return(EXP);
<A>sin return(SIN);
<A>cos return(COS);
<A>atan2 return(ATAN2);
<A>sqrt return(SQRT);
<A>rand return(RAND);
<A>max return(MAX);
<A>min return(MIN);
<A>int return(INT);
<A>print return(PRINT);
<A>sprintf return(SPRINTF);
<A>pic{WS}.* { yylval.p = tostring(yytext+3); return(PIC); }
<A>graph{WS}.* { yylval.p = tostring(yytext+5); return(GRAPH); }
<A>for return(FOR);
<A>^Endfor\n { endfor(); }
<A>do { yylval.p = delimstr("loop body"); BEGIN A; return(DOSTR); }
<A>copy|include { return(COPY); }
<A>thru|through { BEGIN thru; return(THRU); }
<thru>{WS}+ ;
<thru>{A}{B}*|. { yylval.op = copythru(yytext); BEGIN A; return(DEFNAME); }
<A>until return(UNTIL);
<A>if return(IF);
<A>then { yylval.p = delimstr("then part"); BEGIN A; return(THEN); }
<A>else { yylval.p = delimstr("else part"); BEGIN A; return(ELSE); }
<A>next return(NEXT);
<A>draw return(yylval.i = DRAW);
<A>new return(yylval.i = NEW);
<A>plot return(yylval.i = PLOT);
<A>label(s)? return(LABEL);
<A>x return(X);
<A>y return(Y);
<A>top { yylval.i = TOP; return SIDE; }
<A>bot(tom)? { yylval.i = BOT; return SIDE; }
<A>left { yylval.i = LEFT; return SIDE; }
<A>right { yylval.i = RIGHT; return SIDE; }
<A>up return(yylval.i = UP);
<A>down return(yylval.i = DOWN);
<A>across return(yylval.i = ACROSS);
<A>height|ht return(yylval.i = HEIGHT);
<A>wid(th)? return(yylval.i = WIDTH);
<A>rad(ius)? return(yylval.i = RADIUS);
<A>invis return(yylval.i = INVIS);
<A>dot(ted) return(yylval.i = DOT);
<A>dash(ed) return(yylval.i = DASH);
<A>solid return(yylval.i = SOLID);
<A>ljust { yylval.i = LJUST; return JUST; }
<A>rjust { yylval.i = RJUST; return JUST; }
<A>above { yylval.i = ABOVE; return JUST; }
<A>below { yylval.i = BELOW; return JUST; }
<A>size return(yylval.i = SIZE);
<A>from return(yylval.i = FROM);
<A>to return(yylval.i = TO);
<A>by|step return(yylval.i = BY);
<A>at return(yylval.i = AT);
<A>with return(yylval.i = WITH);
<A>in return(yylval.i = IN);
<A>out return(yylval.i = OUT);
<A>off return(yylval.i = OFF);
<A>sh{WS}+ { BEGIN sh;
if ((delim = input()) == '{') {
shcnt = 1;
delim = '}';
}
shell_init();
}
<sh>{A}{B}* {
int c;
Obj *p;
if (yytext[0] == delim) {
shell_exec();
BEGIN A;
} else {
p = lookup(yytext, 0);
if (p != NULL && p->type == DEFNAME) {
c = input();
unput(c);
if (c == '(')
dodef(p);
else
pbstr(p->val);
} else
shell_text(yytext);
}
}
<sh>"{" { shcnt++; shell_text(yytext); }
<sh>"}" { if (delim != '}' || --shcnt > 0)
shell_text(yytext);
else {
shell_exec();
BEGIN A;
}
}
<sh>.|\n { if (yytext[0] == delim) {
shell_exec();
BEGIN A;
} else
shell_text(yytext);
}
<A>define{WS}+ { BEGIN def; }
<def>{A}{B}* { definition(yytext); BEGIN A; }
<A>({D}+("."?){D}*|"."{D}+)((e|E)("+"|-)?{D}+)?i? {
yylval.f = atof(yytext); return(NUMBER); }
<A>^"."[^0-9].* { if (yytext[1] == 'G' && yytext[2] == '2') {
yylval.i = yytext[2];
return(EOF);
} else {
yylval.p = tostring(yytext);
return(PIC);
}
}
<A>{A}{B}* {
int c;
Obj *p;
p = lookup(yytext, 1);
if (p->type == DEFNAME) {
c = input();
unput(c);
if (c == '(') /* it's name(...) */
dodef(p);
else /* no argument list */
pbstr(p->val);
} else {
yylval.op = p;
return p->type; /* NAME or VARNAME */
}
}
<A>"==" return(EQ);
<A>">=" return(GE);
<A>"<=" return(LE);
<A>"!=" return(NE);
<A>">" return(GT);
<A>"<" return(LT);
<A>"&&" return(AND);
<A>"||" return(OR);
<A>"!" return(NOT);
<A>\" { BEGIN str; clen = 0; }
<A>#.* ;
<A>. { yylval.i = yytext[0]; return(yytext[0]); }
<str>\" { BEGIN A; cbuf[clen] = 0;
yylval.p = tostring(cbuf); return(STRING); }
<str>\n { ERROR "newline in string" WARNING; BEGIN A; return(ST); }
<str>"\\\"" { cbuf[clen++] = '\\'; cbuf[clen++] = '"'; }
<str>"\\\\" { cbuf[clen++] = '\\'; cbuf[clen++] = '\\'; }
<str>. { CADD; }
%%

580
src/cmd/grap/input.c Normal file
View file

@ -0,0 +1,580 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "grap.h"
#include "y.tab.h"
Infile infile[10];
Infile *curfile = infile;
#define MAXSRC 50
Src src[MAXSRC]; /* input source stack */
Src *srcp = src;
void pushsrc(int type, char *ptr) /* new input source */
{
if (++srcp >= src + MAXSRC)
ERROR "inputs nested too deep" FATAL;
srcp->type = type;
srcp->sp = ptr;
if (dbg) {
printf("\n%3d ", srcp - src);
switch (srcp->type) {
case File:
printf("push file %s\n", ((Infile *)ptr)->fname);
break;
case Macro:
printf("push macro <%s>\n", ptr);
break;
case Char:
printf("push char <%c>\n", *ptr);
break;
case Thru:
printf("push thru\n");
break;
case String:
printf("push string <%s>\n", ptr);
break;
case Free:
printf("push free <%s>\n", ptr);
break;
default:
ERROR "pushed bad type %d", srcp->type FATAL;
}
}
}
void popsrc(void) /* restore an old one */
{
if (srcp <= src)
ERROR "too many inputs popped" FATAL;
if (dbg) {
printf("%3d ", srcp - src);
switch (srcp->type) {
case File:
printf("pop file\n");
break;
case Macro:
printf("pop macro\n");
break;
case Char:
printf("pop char <%c>\n", *srcp->sp);
break;
case Thru:
printf("pop thru\n");
break;
case String:
printf("pop string\n");
break;
case Free:
printf("pop free\n");
break;
default:
ERROR "pop weird input %d", srcp->type FATAL;
}
}
srcp--;
}
void definition(char *s) /* collect definition for s and install */
/* definitions picked up lexically */
{
char *p;
Obj *stp;
p = delimstr("definition");
stp = lookup(s, 0);
if (stp != NULL) { /* it's there before */
if (stp->type != DEFNAME) {
ERROR "%s used as variable and definition", s WARNING;
return;
}
free(stp->val);
} else {
stp = lookup(s, 1);
stp->type = DEFNAME;
}
stp->val = p;
dprintf("installing %s as `%s'\n", s, p);
}
char *delimstr(char *s) /* get body of X ... X */
/* message if too big */
{
int c, delim, rdelim, n, deep;
static char *buf = NULL;
static int nbuf = 0;
char *p;
if (buf == NULL)
buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
while ((delim = input()) == ' ' || delim == '\t' || delim == '\n')
;
rdelim = baldelim(delim, "{}"); /* could be "(){}[]`'" */
deep = 1;
for (p = buf; ; ) {
c = input();
if (c == rdelim)
if (--deep == 0)
break;
if (c == delim)
deep++;
if (p >= buf + nbuf) {
n = p - buf;
buf = grow(buf, "buf", nbuf += 1000, sizeof(buf[0]));
p = buf + n;
}
if (c == EOF)
ERROR "end of file in %s %c %.20s... %c", s, delim, buf, delim FATAL;
*p++ = c;
}
*p = '\0';
dprintf("delimstr %s %c <%s> %c\n", s, delim, buf, delim);
return tostring(buf);
}
baldelim(int c, char *s) /* replace c by balancing entry in s */
{
for ( ; *s; s += 2)
if (*s == c)
return s[1];
return c;
}
Arg args[10]; /* argument frames */
Arg *argfp = args; /* frame pointer */
int argcnt; /* number of arguments seen so far */
void dodef(Obj *stp) /* collect args and switch input to defn */
{
int i, len;
char *p;
Arg *ap;
ap = argfp+1;
if (ap >= args+10)
ERROR "arguments too deep" FATAL;
argcnt = 0;
if (input() != '(')
ERROR "disaster in dodef" FATAL;
if (ap->argval == 0)
ap->argval = malloc(1000);
for (p = ap->argval; (len = getarg(p)) != -1; p += len) {
ap->argstk[argcnt++] = p;
if (input() == ')')
break;
}
for (i = argcnt; i < MAXARGS; i++)
ap->argstk[i] = "";
if (dbg)
for (i = 0; i < argcnt; i++)
printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
argfp = ap;
pushsrc(Macro, stp->val);
}
getarg(char *p) /* pick up single argument, store in p, return length */
{
int n, c, npar;
n = npar = 0;
for ( ;; ) {
c = input();
if (c == EOF)
ERROR "end of file in getarg!" FATAL;
if (npar == 0 && (c == ',' || c == ')'))
break;
if (c == '"') /* copy quoted stuff intact */
do {
*p++ = c;
n++;
} while ((c = input()) != '"' && c != EOF);
else if (c == '(')
npar++;
else if (c == ')')
npar--;
n++;
*p++ = c;
}
*p = 0;
unput(c);
return(n + 1);
}
#define PBSIZE 2000
char pbuf[PBSIZE]; /* pushback buffer */
char *pb = pbuf-1; /* next pushed back character */
char ebuf[200]; /* collect input here for error reporting */
char *ep = ebuf;
int begin = 0;
extern int thru;
extern Obj *thrudef;
extern char *untilstr;
input(void)
{
register int c;
if (thru && begin) {
do_thru();
begin = 0;
}
c = nextchar();
dprintf(" <%c>", c);
if (ep >= ebuf + sizeof ebuf)
ep = ebuf;
return *ep++ = c;
}
nextchar(void)
{
register int c;
loop:
switch (srcp->type) {
case Free: /* free string */
free(srcp->sp);
popsrc();
goto loop;
case Thru: /* end of pushed back line */
begin = 1;
popsrc();
c = '\n';
break;
case Char:
if (pb >= pbuf) {
c = *pb--;
popsrc();
break;
} else { /* can't happen? */
popsrc();
goto loop;
}
case String:
c = *srcp->sp++;
if (c == '\0') {
popsrc();
goto loop;
} else {
if (*srcp->sp == '\0') /* empty, so pop */
popsrc();
break;
}
case Macro:
c = *srcp->sp++;
if (c == '\0') {
if (--argfp < args)
ERROR "argfp underflow" FATAL;
popsrc();
goto loop;
} else if (c == '$' && isdigit(*srcp->sp)) { /* $3 */
int n = 0;
while (isdigit(*srcp->sp))
n = 10 * n + *srcp->sp++ - '0';
if (n > 0 && n <= MAXARGS)
pushsrc(String, argfp->argstk[n-1]);
goto loop;
}
break;
case File:
c = getc(curfile->fin);
if (c == EOF) {
if (curfile == infile)
ERROR "end of file inside .G1/.G2" FATAL;
if (curfile->fin != stdin) {
fclose(curfile->fin);
free(curfile->fname); /* assumes allocated */
}
curfile--;
printf(".lf %d %s\n", curfile->lineno, curfile->fname);
popsrc();
thru = 0; /* chicken out */
thrudef = 0;
if (untilstr) {
free(untilstr);
untilstr = 0;
}
goto loop;
}
if (c == '\n')
curfile->lineno++;
break;
}
return c;
}
void do_thru(void) /* read one line, make into a macro expansion */
{
int c, i;
char *p;
Arg *ap;
ap = argfp+1;
if (ap >= args+10)
ERROR "arguments too deep" FATAL;
if (ap->argval == NULL)
ap->argval = malloc(1000);
p = ap->argval;
argcnt = 0;
c = nextchar();
if (thru == 0) { /* end of file was seen, so thru is done */
unput(c);
return;
}
for ( ; c != '\n' && c != EOF; ) {
if (c == ' ' || c == '\t') {
c = nextchar();
continue;
}
if (argcnt >= MAXARGS)
ERROR "too many fields on input line" FATAL;
ap->argstk[argcnt++] = p;
if (c == '"') {
do {
*p++ = c;
if ((c = nextchar()) == '\\') {
*p++ = c;
*p++ = nextchar();
c = nextchar();
}
} while (c != '"' && c != '\n' && c != EOF);
*p++ = '"';
if (c == '"')
c = nextchar();
} else {
do {
*p++ = c;
} while ((c = nextchar())!=' ' && c!='\t' && c!='\n' && c!=',' && c!=EOF);
if (c == ',')
c = nextchar();
}
*p++ = '\0';
}
if (c == EOF)
ERROR "unexpected end of file in do_thru" FATAL;
if (argcnt == 0) { /* ignore blank line */
pushsrc(Thru, (char *) 0);
return;
}
for (i = argcnt; i < MAXARGS; i++)
ap->argstk[i] = "";
if (dbg)
for (i = 0; i < argcnt; i++)
printf("arg %d.%d = <%s>\n", ap-args, i+1, ap->argstk[i]);
if (strcmp(ap->argstk[0], ".G2") == 0) {
thru = 0;
thrudef = 0;
pushsrc(String, "\n.G2\n");
return;
}
if (untilstr && strcmp(ap->argstk[0], untilstr) == 0) {
thru = 0;
thrudef = 0;
free(untilstr);
untilstr = 0;
return;
}
pushsrc(Thru, (char *) 0);
dprintf("do_thru pushing back <%s>\n", thrudef->val);
argfp = ap;
pushsrc(Macro, thrudef->val);
}
unput(int c)
{
if (++pb >= pbuf + sizeof pbuf)
ERROR "pushback overflow" FATAL;
if (--ep < ebuf)
ep = ebuf + sizeof(ebuf) - 1;
*pb = c;
pushsrc(Char, pb);
return c;
}
void pbstr(char *s)
{
pushsrc(String, s);
}
double errcheck(double x, char *s)
{
extern int errno;
if (errno == EDOM) {
errno = 0;
ERROR "%s argument out of domain", s WARNING;
} else if (errno == ERANGE) {
errno = 0;
ERROR "%s result out of range", s WARNING;
}
return x;
}
char errbuf[200];
void yyerror(char *s)
{
extern char *cmdname;
int ern = errno; /* cause some libraries clobber it */
if (synerr)
return;
fflush(stdout);
fprintf(stderr, "%s: %s", cmdname, s);
if (ern > 0) {
errno = ern;
perror("???");
}
fprintf(stderr, " near %s:%d\n",
curfile->fname, curfile->lineno+1);
eprint();
synerr = 1;
errno = 0;
}
void eprint(void) /* try to print context around error */
{
char *p, *q;
p = ep - 1;
if (p > ebuf && *p == '\n')
p--;
for ( ; p >= ebuf && *p != '\n'; p--)
;
while (*p == '\n')
p++;
fprintf(stderr, " context is\n\t");
for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
;
for (; p < q; p++)
if (isprint(*p))
putc(*p, stderr);
fprintf(stderr, " >>> ");
for (; p < q; p++)
if (isprint(*p))
putc(*p, stderr);
fprintf(stderr, " <<< ");
while (pb >= pbuf)
putc(*pb--, stderr);
fgets(ebuf, sizeof ebuf, curfile->fin);
fprintf(stderr, "%s", ebuf);
pbstr("\n.G2\n"); /* safety first */
ep = ebuf;
}
int yywrap(void) {return 1;}
char *newfile = 0; /* filename for file copy */
char *untilstr = 0; /* string that terminates a thru */
int thru = 0; /* 1 if copying thru macro */
Obj *thrudef = 0; /* macro being used */
void copyfile(char *s) /* remember file to start reading from */
{
newfile = s;
}
void copydef(Obj *p) /* remember macro Obj */
{
thrudef = p;
}
Obj *copythru(char *s) /* collect the macro name or body for thru */
{
Obj *p;
char *q;
p = lookup(s, 0);
if (p != NULL) {
if (p->type == DEFNAME) {
p->val = addnewline(p->val);
return p;
} else
ERROR "%s used as define and name", s FATAL;
}
/* have to collect the definition */
pbstr(s); /* first char is the delimiter */
q = delimstr("thru body");
p = lookup("nameless", 1);
if (p != NULL)
if (p->val)
free(p->val);
p->type = DEFNAME;
p->val = q;
p->val = addnewline(p->val);
dprintf("installing nameless as `%s'\n", p->val);
return p;
}
char *addnewline(char *p) /* add newline to end of p */
{
int n;
n = strlen(p);
if (p[n-1] != '\n') {
p = realloc(p, n+2);
p[n] = '\n';
p[n+1] = '\0';
}
return p;
}
void copyuntil(char *s) /* string that terminates a thru */
{
untilstr = s;
}
void copy(void) /* begin input from file, etc. */
{
FILE *fin;
if (newfile) {
if ((fin = fopen(unsharp(newfile), "r")) == NULL)
ERROR "can't open file %s", newfile FATAL;
curfile++;
curfile->fin = fin;
curfile->fname = tostring(newfile);
curfile->lineno = 0;
printf(".lf 1 %s\n", curfile->fname);
pushsrc(File, curfile->fname);
newfile = 0;
}
if (thrudef) {
thru = 1;
begin = 1; /* wrong place */
}
}
char shellbuf[1000], *shellp;
void shell_init(void) /* set up to interpret a shell command */
{
fprintf(tfd, "# shell cmd...\n");
sprintf(shellbuf, "rc -c '");
shellp = shellbuf + strlen(shellbuf);
}
void shell_text(char *s) /* add string to command being collected */
{
/* fprintf(tfd, "#add <%s> to <%s>\n", s, shellbuf); */
while (*s) {
if (*s == '\'') { /* protect interior quotes */
*shellp++ = '\'';
*shellp++ = '\\';
*shellp++ = '\'';
}
*shellp++ = *s++;
}
}
void shell_exec(void) /* do it */
{
/* fprintf(tfd, "# run <%s>\n", shellbuf); */
*shellp++ = '\'';
*shellp = '\0';
system(shellbuf);
}

123
src/cmd/grap/label.c Normal file
View file

@ -0,0 +1,123 @@
#include <stdio.h>
#include <string.h>
#include "grap.h"
#include "y.tab.h"
int pointsize = 10; /* assumed pointsize to start */
int ps_set = 0; /* someone has set pointsize explicitly */
double textht = 1.0/6.0; /* 6 lines/inch */
double textwid = 1; /* width of text box for vertical */
double lab_up = 0.0; /* extra motion for label */
double lab_rt = 0.0; /* extra motion for label */
double lab_wid = 0.0; /* override default width computation */
void labelwid(double amt)
{
lab_wid = amt + .00001;
}
void labelmove(int dir, double amt) /* record direction & motion of position corr */
{
switch (dir) {
case UP: lab_up += amt; break;
case DOWN: lab_up -= amt; break;
case LEFT: lab_rt -= amt; break;
case RIGHT: lab_rt += amt; break;
}
}
void label(int label_side, Attr *stringlist) /* stick label on label_side */
{
int m;
Attr *ap;
fprintf(tfd, "\ttextht = %g\n", textht);
if (lab_wid != 0.0) {
fprintf(tfd, "\ttextwid = %g\n", lab_wid);
lab_wid = 0;
} else if (label_side == LEFT || label_side == RIGHT) {
textwid = 0;
for (ap = stringlist; ap != NULL; ap = ap->next)
if ((m = strlen(ap->sval)) > textwid)
textwid = m;
textwid /= 15; /* estimate width at 15 chars/inch */
fprintf(tfd, "\ttextwid = %g\n", textwid);
}
fprintf(tfd, "Label:\t%s", slprint(stringlist));
freeattr(stringlist);
switch (label_side) {
case BOT:
case 0:
fprintf(tfd, " with .n at Frame.s - (0,2 * textht)");
break;
case LEFT:
fprintf(tfd, " wid textwid with .e at Frame.w - (0.2,0)");
break;
case RIGHT:
fprintf(tfd, " wid textwid with .w at Frame.e + (0.2,0)");
break;
case TOP:
fprintf(tfd, " with .s at Frame.n + (0,2 * textht)");
break;
}
lab_adjust();
fprintf(tfd, "\n");
label_side = BOT;
}
void lab_adjust(void) /* add a string to adjust labels, ticks, etc. */
{
if (lab_up != 0.0 || lab_rt != 0.0)
fprintf(tfd, " + (%g,%g)", lab_rt, lab_up);
}
char *sizeit(Attr *ap) /* add \s..\s to ap->sval */
{
int n;
static char buf[1000];
if (!ap->op) { /* no explicit size command */
if (ps_set) {
sprintf(buf, "\\s%d%s\\s0", pointsize, ap->sval);
return buf;
} else
return ap->sval;
} else if (!ps_set) { /* explicit size but no global size */
n = (int) ap->fval;
switch (ap->op) {
case ' ': /* absolute size */
sprintf(buf, "\\s%d%s\\s0", n, ap->sval);
break;
case '+': /* better be only one digit! */
sprintf(buf, "\\s+%d%s\\s-%d", n, ap->sval, n);
break;
case '-':
sprintf(buf, "\\s-%d%s\\s+%d", n, ap->sval, n);
break;
case '*':
case '/':
return ap->sval; /* ignore for now */
}
return buf;
} else {
/* explicit size and a global background size */
n = (int) ap->fval;
switch (ap->op) {
case ' ': /* absolute size */
sprintf(buf, "\\s%d%s\\s0", n, ap->sval);
break;
case '+':
sprintf(buf, "\\s%d%s\\s0", pointsize+n, ap->sval);
break;
case '-':
sprintf(buf, "\\s%d%s\\s0", pointsize-n, ap->sval);
break;
case '*':
case '/':
return ap->sval; /* ignore for now */
}
return buf;
}
}

164
src/cmd/grap/main.c Normal file
View file

@ -0,0 +1,164 @@
#include <stdio.h>
#include <signal.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "grap.h"
#include "y.tab.h"
int dbg = 0;
#ifndef GRAPDEFINES
#define GRAPDEFINES "#9/sys/lib/grap.defines"
#endif
char *lib_defines = GRAPDEFINES;
int lib = 1; /* 1 to include lib_defines */
FILE *tfd = NULL;
char tempfile[L_tmpnam];
int synerr = 0;
int codegen = 0; /* 1=>output for this picture; 0=>no output */
char *cmdname;
Obj *objlist = NULL; /* all names stored here */
#define BIG 1e30
Point ptmin = { NULL, -BIG, -BIG };
Point ptmax = { NULL, BIG, BIG };
char *version = "version Dec 30, 1995";
extern int yyparse(void);
extern void setdefaults(void);
extern void getdata(void);
extern int unlink(char *);
main(int argc, char *argv[])
{
extern void onintr(int), fpecatch(int);
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, onintr);
signal(SIGFPE, fpecatch);
cmdname = argv[0];
tmpnam(tempfile);
while (argc > 1 && *argv[1] == '-') {
switch (argv[1][1]) {
case 'd':
dbg = 1;
tfd = stdout;
strcpy(tempfile, "grap.temp");
unlink(tempfile);
fprintf(stderr, "%s\n", version);
break;
case 'l': /* turn off /usr/lib inclusion */
lib = 0;
break;
}
argc--;
argv++;
}
setdefaults();
curfile = infile;
if (argc <= 1) {
curfile->fin = stdin;
curfile->fname = tostring("-");
pushsrc(File, curfile->fname);
getdata();
} else
while (argc-- > 1) {
if ((curfile->fin = fopen(*++argv, "r")) == NULL) {
fprintf(stderr, "grap: can't open %s\n", *argv);
onintr(0);
}
curfile->fname = tostring(*argv);
pushsrc(File, curfile->fname);
getdata();
fclose(curfile->fin);
free(curfile->fname);
}
if (!dbg)
unlink(tempfile);
exit(0);
}
void onintr(int n)
{
n;
if (!dbg)
unlink(tempfile);
exit(1);
}
void fpecatch(int n)
{
ERROR "floating point exception" WARNING;
onintr(n);
}
char *grow(char *ptr, char *name, int num, int size) /* make array bigger */
{
char *p;
if (ptr == NULL)
p = malloc(num * size);
else
p = realloc(ptr, num * size);
if (p == NULL)
ERROR "can't grow %s to %d", name, num * size FATAL;
return p;
}
static struct {
char *name;
double val;
} defaults[] ={
"frameht", FRAMEHT,
"framewid", FRAMEWID,
"ticklen", TICKLEN,
"slop", SLOP,
NULL, 0
};
void setdefaults(void) /* set default sizes for variables */
{
int i;
Obj *p;
for (i = 0; defaults[i].name != NULL; i++) {
p = lookup(defaults[i].name, 1);
setvar(p, defaults[i].val);
}
}
void getdata(void) /* read input */
{
register FILE *fin;
char buf[1000], buf1[100];
int ln;
fin = curfile->fin;
curfile->lineno = 0;
printf(".lf 1 %s\n", curfile->fname);
while (fgets(buf, sizeof buf, fin) != NULL) {
curfile->lineno++;
if (*buf == '.' && *(buf+1) == 'G' && *(buf+2) == '1') {
setup();
fprintf(stdout, ".PS%s", &buf[3]); /* maps .G1 [w] to .PS w */
printf("scale = 1\n"); /* defends against cip users */
printf(".lf %d\n", curfile->lineno+1);
yyparse();
fprintf(stdout, ".PE\n");
printf(".lf %d\n", curfile->lineno+1);
fflush(stdout);
} else if (buf[0] == '.' && buf[1] == 'l' && buf[2] == 'f') {
if (sscanf(buf+3, "%d %s", &ln, buf1) == 2) {
free(curfile->fname);
printf(".lf %d %s\n", curfile->lineno = ln, curfile->fname = tostring(buf1));
} else
printf(".lf %d\n", curfile->lineno = ln);
} else
fputs(buf, stdout);
}
}

263
src/cmd/grap/misc.c Normal file
View file

@ -0,0 +1,263 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "grap.h"
#include "y.tab.h"
int nnum = 0; /* number of saved numbers */
double num[MAXNUM];
int just; /* current justification mode (RJUST, etc.) */
int sizeop; /* current optional operator for size change */
double sizexpr; /* current size change expression */
void savenum(int n, double f) /* save f in num[n] */
{
num[n] = f;
nnum = n+1;
if (nnum >= MAXNUM)
ERROR "too many numbers" WARNING;
}
void setjust(int j)
{
just |= j;
}
void setsize(int op, double expr)
{
sizeop = op;
sizexpr = expr;
}
char *tostring(char *s)
{
register char *p;
p = malloc(strlen(s)+1);
if (p == NULL)
ERROR "out of space in tostring on %s", s FATAL;
strcpy(p, s);
return(p);
}
void range(Point pt) /* update the range for point pt */
{
Obj *p = pt.obj;
if (!(p->coord & XFLAG)) {
if (pt.x > p->pt1.x)
p->pt1.x = pt.x;
if (pt.x < p->pt.x)
p->pt.x = pt.x;
}
if (!(p->coord & YFLAG)) {
if (pt.y > p->pt1.y)
p->pt1.y = pt.y;
if (pt.y < p->pt.y)
p->pt.y = pt.y;
}
}
void halfrange(Obj *p, int side, double val) /* record max and min for one direction */
{
if (!(p->coord&XFLAG) && (side == LEFT || side == RIGHT)) {
if (val < p->pt.y)
p->pt.y = val;
if (val > p->pt1.y)
p->pt1.y = val;
} else if (!(p->coord&YFLAG) && (side == TOP || side == BOT)) {
if (val < p->pt.x)
p->pt.x = val;
if (val > p->pt1.x)
p->pt1.x = val;
}
}
Obj *lookup(char *s, int inst) /* find s in objlist, install if inst */
{
Obj *p;
int found = 0;
for (p = objlist; p; p = p->next){
if (strcmp(s, p->name) == 0) {
found = 1;
break;
}
}
if (p == NULL && inst != 0) {
p = (Obj *) calloc(1, sizeof(Obj));
if (p == NULL)
ERROR "out of space in lookup" FATAL;
p->name = tostring(s);
p->type = NAME;
p->pt = ptmax;
p->pt1 = ptmin;
p->fval = 0.0;
p->next = objlist;
objlist = p;
}
dprintf("lookup(%s,%d) = %d\n", s, inst, found);
return p;
}
double getvar(Obj *p) /* return value of variable */
{
return p->fval;
}
double setvar(Obj *p, double f) /* set value of variable to f */
{
if (strcmp(p->name, "pointsize") == 0) { /* kludge */
pointsize = f;
ps_set = 1;
}
p->type = VARNAME;
return p->fval = f;
}
Point makepoint(Obj *s, double x, double y) /* make a Point */
{
Point p;
dprintf("makepoint: %s, %g,%g\n", s->name, x, y);
p.obj = s;
p.x = x;
p.y = y;
return p;
}
Attr *makefattr(int type, double fval) /* set double in attribute */
{
return makeattr(type, fval, (char *) 0, 0, 0);
}
Attr *makesattr(char *s) /* make an Attr cell containing s */
{
Attr *ap = makeattr(STRING, sizexpr, s, just, sizeop);
just = sizeop = 0;
sizexpr = 0.0;
return ap;
}
Attr *makeattr(int type, double fval, char *sval, int just, int op)
{
Attr *a;
a = (Attr *) malloc(sizeof(Attr));
if (a == NULL)
ERROR "out of space in makeattr" FATAL;
a->type = type;
a->fval = fval;
a->sval = sval;
a->just = just;
a->op = op;
a->next = NULL;
return a;
}
Attr *addattr(Attr *a1, Attr *ap) /* add attr ap to end of list a1 */
{
Attr *p;
if (a1 == 0)
return ap;
if (ap == 0)
return a1;
for (p = a1; p->next; p = p->next)
;
p->next = ap;
return a1;
}
void freeattr(Attr *ap) /* free an attribute list */
{
Attr *p;
while (ap) {
p = ap->next; /* save next */
if (ap->sval)
free(ap->sval);
free((char *) ap);
ap = p;
}
}
char *slprint(Attr *stringlist) /* print strings from stringlist */
{
int ntext, n, last_op, last_just;
double last_fval;
static char buf[1000];
Attr *ap;
buf[0] = '\0';
last_op = last_just = 0;
last_fval = 0.0;
for (ntext = 0, ap = stringlist; ap != NULL; ap = ap->next)
ntext++;
sprintf(buf, "box invis wid 0 ht %d*textht", ntext);
n = strlen(buf);
for (ap = stringlist; ap != NULL; ap = ap->next) {
if (ap->op == 0) { /* propagate last value */
ap->op = last_op;
ap->fval = last_fval;
} else {
last_op = ap->op;
last_fval = ap->fval;
}
sprintf(buf+n, " \"%s\"", ps_set || ap->op ? sizeit(ap) : ap->sval);
if (ap->just)
last_just = ap->just;
if (last_just)
strcat(buf+n, juststr(last_just));
n = strlen(buf);
}
return buf; /* watch it: static */
}
char *juststr(int j) /* convert RJUST, etc., into string */
{
static char buf[50];
buf[0] = '\0';
if (j & RJUST)
strcat(buf, " rjust");
if (j & LJUST)
strcat(buf, " ljust");
if (j & ABOVE)
strcat(buf, " above");
if (j & BELOW)
strcat(buf, " below");
return buf; /* watch it: static */
}
char *sprntf(char *s, Attr *ap) /* sprintf(s, attrlist ap) */
{
char buf[500];
int n;
Attr *p;
for (n = 0, p = ap; p; p = p->next)
n++;
switch (n) {
case 0:
return s;
case 1:
sprintf(buf, s, ap->fval);
break;
case 2:
sprintf(buf, s, ap->fval, ap->next->fval);
break;
case 3:
sprintf(buf, s, ap->fval, ap->next->fval, ap->next->next->fval);
break;
case 5:
ERROR "too many expressions in sprintf" WARNING;
case 4:
sprintf(buf, s, ap->fval, ap->next->fval, ap->next->next->fval, ap->next->next->next->fval);
break;
}
free(s);
return tostring(buf);
}

37
src/cmd/grap/mkfile Normal file
View file

@ -0,0 +1,37 @@
<$PLAN9/src/mkhdr
TARG=grap
OFILES=\
grap.$O\
grapl.$O\
main.$O\
input.$O\
print.$O\
frame.$O\
for.$O\
coord.$O\
ticks.$O\
plot.$O\
label.$O\
misc.$O\
HFILES=grap.h\
y.tab.h\
YFILES=grap.y\
LFILES=grapl.lx\
SHORTLIB=bio 9
<$PLAN9/src/mkone
YFLAGS = -d -S
LEX=9lex
grap.c: y.tab.c
mv $prereq $target
grapl.c: $LFILES
$LEX -t $prereq > $target
clean:V:
rm -f [$OS].out *.[$OS] y.tab.? lex.yy.c grapl.c grap.c grap

132
src/cmd/grap/plot.c Normal file
View file

@ -0,0 +1,132 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "grap.h"
#include "y.tab.h"
void line(int type, Point p1, Point p2, Attr *desc) /* draw a line segment */
{
fprintf(tfd, "%s %s from %s",
type==LINE ? "line" : "arrow", desc_str(desc), xyname(p1));
fprintf(tfd, " to %s", xyname(p2)); /* 'cause xyname is botched */
fprintf(tfd, "\n");
range(p1);
range(p2);
}
void circle(double r, Point pt) /* draw a circle */
{
if (r > 0.0)
fprintf(tfd, "circle rad %g at %s\n", r, xyname(pt));
else
fprintf(tfd, "\"\\s-3\\(ob\\s0\" at %s\n", xyname(pt));
range(pt);
}
char *xyname(Point pt) /* generate xy name macro for point p */
{
static char buf[200];
Obj *p;
p = pt.obj;
if (p->log & XFLAG) {
if (pt.x <= 0.0)
ERROR "can't take log of x coord %g", pt.x FATAL;
logit(pt.x);
}
if (p->log & YFLAG) {
if (pt.y <= 0.0)
ERROR "can't take log of y coord %g", pt.y FATAL;
logit(pt.y);
}
sprintf(buf, "xy_%s(%g,%g)", p->name, pt.x, pt.y);
return buf; /* WATCH IT: static */
}
void pic(char *s) /* fire out pic stuff directly */
{
while (*s == ' ')
s++;
fprintf(tfd, "%s\n", s);
}
int auto_x = 0; /* counts abscissa if none provided */
void numlist(void) /* print numbers in default way */
{
Obj *p;
Point pt;
int i;
static char *spot = "\\(bu";
Attr *ap;
p = pt.obj = lookup(curr_coord, 1);
if (nnum == 1) {
nnum = 2;
num[1] = num[0];
num[0] = ++auto_x;
}
pt.x = num[0];
if (p->attr && p->attr->sval)
spot = p->attr->sval;
for (i = 1; i < nnum; i++) {
pt.y = num[i];
if (p->attr == 0 || p->attr->type == 0) {
ap = makesattr(tostring(spot));
plot(ap, pt);
} else
next(p, pt, p->attr);
}
nnum = 0;
}
void plot(Attr *sl, Point pt) /* put stringlist sl at point pt */
{
fprintf(tfd, "%s at %s\n", slprint(sl), xyname(pt));
range(pt);
freeattr(sl);
}
void plotnum(double f, char *fmt, Point pt) /* plot value f at point */
{
char buf[100];
if (fmt) {
sprintf(buf, fmt, f);
free(fmt);
} else if (f >= 0.0)
sprintf(buf, "%g", f);
else
sprintf(buf, "\\-%g", -f);
fprintf(tfd, "\"%s\" at %s\n", buf, xyname(pt));
range(pt);
}
void drawdesc(int type, Obj *p, Attr *desc, char *s) /* set line description for p */
{
p->attr = desc;
p->attr->sval = s;
if (type == NEW) {
p->first = 0; /* so it really looks new */
auto_x = 0;
}
}
void next(Obj *p, Point pt, Attr *desc) /* add component to a path */
{
char *s;
if (p->first == 0) {
p->first++;
fprintf(tfd, "L%s: %s\n", p->name, xyname(pt));
} else {
fprintf(tfd, "line %s from L%s to %s; L%s: Here\n",
desc_str(desc->type ? desc : p->attr),
p->name, xyname(pt), p->name);
}
if (p->attr && (s=p->attr->sval)) {
/* BUG: should fix size here */
fprintf(tfd, "\"%s\" at %s\n", s, xyname(pt));
}
range(pt);
}

236
src/cmd/grap/print.c Normal file
View file

@ -0,0 +1,236 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include "grap.h"
#include "y.tab.h"
double margin = MARGIN; /* extra space around edges */
extern double frame_ht, frame_wid, ticklen;
extern int just, sizeop, tick_dir;
extern double sizexpr, lab_up, lab_rt;
char graphname[50] = "Graph";
char graphpos[200] = "";
void print(void) /* arrange final output */
{
FILE *fd;
Obj *p, *dfp;
int c;
double dx, dy, xfac, yfac;
if (tfd != NULL) {
fclose(tfd); /* end the temp file */
tfd = stdout;
}
if ((p=lookup("margin",0)) != NULL)
margin = p->fval;
if (frame_ht < 0) /* wasn't set explicitly, so use default */
frame_ht = getvar(lookup("frameht", 0));
if (frame_wid < 0)
frame_wid = getvar(lookup("framewid", 0));
dfp = NULL;
for (p = objlist; p; p = p->next) {
dprintf("print: name = <%s>, type = %d\n", p->name, p->type);
if (p->type == NAME) {
Point pt, pt1;
pt = p->pt;
pt1 = p->pt1;
fprintf(tfd, "\t# %s %g .. %g, %g .. %g\n",
p->name, pt.x, pt1.x, pt.y, pt1.y);
if (p->log & XFLAG) {
if (pt.x <= 0.0)
ERROR "can't take log of x coord %g", pt.x FATAL;
logit(pt.x);
logit(pt1.x);
}
if (p->log & YFLAG) {
if (pt.y <= 0.0)
ERROR "can't take log of y coord %g", pt.y FATAL;
logit(pt.y);
logit(pt1.y);
}
if (!(p->coord & XFLAG)) {
dx = pt1.x - pt.x;
pt.x -= margin * dx;
pt1.x += margin * dx;
}
if (!(p->coord & YFLAG)) {
dy = pt1.y - pt.y;
pt.y -= margin * dy;
pt1.y += margin * dy;
}
if (autoticks && strcmp(p->name, dflt_coord) == 0) {
p->pt = pt;
p->pt1 = pt1;
if (p->log & XFLAG) {
p->pt.x = pow(10.0, pt.x);
p->pt1.x = pow(10.0, pt1.x);
}
if (p->log & YFLAG) {
p->pt.y = pow(10.0, pt.y);
p->pt1.y = pow(10.0, pt1.y);
}
dfp = setauto();
}
dx = pt1.x - pt.x;
dy = pt1.y - pt.y;
xfac = dx > 0 ? frame_wid/dx : frame_wid/2;
yfac = dy > 0 ? frame_ht/dy : frame_ht/2;
fprintf(tfd, "define xy_%s @ ", p->name);
if (dx > 0)
fprintf(tfd, "\t(($1)-(%g))*%g", pt.x, xfac);
else
fprintf(tfd, "\t%g", xfac);
if (dy > 0)
fprintf(tfd, ", (($2)-(%g))*%g @\n", pt.y, yfac);
else
fprintf(tfd, ", %g @\n", yfac);
fprintf(tfd, "define x_%s @ ", p->name);
if (dx > 0)
fprintf(tfd, "\t(($1)-(%g))*%g @\n", pt.x, xfac);
else
fprintf(tfd, "\t%g @\n", xfac);
fprintf(tfd, "define y_%s @ ", p->name);
if (dy > 0)
fprintf(tfd, "\t(($1)-(%g))*%g @\n", pt.y, yfac);
else
fprintf(tfd, "\t%g @\n", yfac);
}
}
if (codegen)
frame();
if (codegen && autoticks && dfp)
do_autoticks(dfp);
if ((fd = fopen(tempfile, "r")) != NULL) {
while ((c = getc(fd)) != EOF)
putc(c, tfd);
fclose(fd);
}
tfd = NULL;
}
void endstat(void) /* clean up after each statement */
{
just = sizeop = 0;
lab_up = lab_rt = 0.0;
sizexpr = 0.0;
nnum = 0;
ntick = 0;
tside = 0;
tick_dir = OUT;
ticklen = TICKLEN;
}
void graph(char *s) /* graph statement */
{
char *p, *os;
int c;
if (codegen) {
fprintf(stdout, "%s: [\n", graphname);
print(); /* pump out previous graph */
fprintf(stdout, "\n] %s\n", graphpos);
reset();
}
if (s) {
dprintf("into graph with <%s>\n", s);
opentemp();
os = s;
while ((c = *s) == ' ' || c == '\t')
s++;
if (c == '\0')
ERROR "no name on graph statement" WARNING;
if (!isupper(s[0]))
ERROR "graph name %s must be capitalized", s WARNING;
for (p=graphname; (c = *s) != ' ' && c != '\t' && c != '\0'; )
*p++ = *s++;
*p = '\0';
strcpy(graphpos, s);
dprintf("graphname = <%s>, graphpos = <%s>\n", graphname, graphpos);
free(os);
}
}
void setup(void) /* done at each .G1 */
{
static int firstG1 = 0;
reset();
opentemp();
frame_ht = frame_wid = -1; /* reset in frame() */
ticklen = getvar(lookup("ticklen", 0));
if (firstG1++ == 0)
do_first();
codegen = synerr = 0;
strcpy(graphname, "Graph");
strcpy(graphpos, "");
}
void do_first(void) /* done at first .G1: definitions, etc. */
{
extern int lib;
extern char *lib_defines;
static char buf[50], buf1[50]; /* static because pbstr uses them */
FILE *fp;
extern int getpid(void);
sprintf(buf, "define pid /%d/\n", getpid());
pbstr(buf);
if (lib != 0) {
if ((fp = fopen(unsharp(lib_defines), "r")) != NULL) {
sprintf(buf1, "copy \"%s\"\n", lib_defines);
pbstr(buf1);
fclose(fp);
} else {
fprintf(stderr, "grap warning: can't open %s\n", lib_defines);
}
}
}
void reset(void) /* done at each "graph ..." statement */
{
Obj *p, *np, *deflist;
extern int tlist, toffside, autodir;
curr_coord = dflt_coord;
ncoord = auto_x = 0;
autoticks = LEFT|BOT;
autodir = 0;
tside = tlist = toffside = 0;
tick_dir = OUT;
margin = MARGIN;
deflist = NULL;
for (p = objlist; p; p = np) {
np = p->next;
if (p->type == DEFNAME || p->type == VARNAME) {
p->next = deflist;
deflist = p;
} else {
free(p->name);
freeattr(p->attr);
free((char *) p);
}
}
objlist = deflist;
}
void opentemp(void)
{
if (tfd != NULL)
fclose(tfd);
if (tfd != stdout) {
// if (tfd != NULL)
// fclose(tfd);
if ((tfd = fopen(tempfile, "w")) == NULL) {
fprintf(stderr, "grap: can't open %s\n", tempfile);
exit(1);
}
}
}

492
src/cmd/grap/ticks.c Normal file
View file

@ -0,0 +1,492 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "grap.h"
#include "y.tab.h"
#define MAXTICK 200
int ntick = 0;
double tickval[MAXTICK]; /* tick values (one axis at a time */
char *tickstr[MAXTICK]; /* and labels */
int tside = 0;
int tlist = 0; /* 1 => explicit values given */
int toffside = 0; /* no ticks on these sides */
int goffside = 0; /* no ticks on grid on these sides */
int tick_dir = OUT;
double ticklen = TICKLEN; /* default tick length */
int autoticks = LEFT|BOT;
int autodir = 0; /* set LEFT, etc. if automatic ticks go in */
void savetick(double f, char *s) /* remember tick location and label */
{
if (ntick >= MAXTICK)
ERROR "too many ticks (%d)", MAXTICK FATAL;
tickval[ntick] = f;
tickstr[ntick] = s;
ntick++;
}
void dflt_tick(double f)
{
if (f >= 0.0)
savetick(f, tostring("%g"));
else
savetick(f, tostring("\\%g"));
}
void tickside(int n) /* remember which side these ticks/gridlines go on */
{
tside |= n;
}
void tickoff(int side) /* remember explicit sides */
{
toffside |= side;
}
void gridtickoff(void) /* turn grid ticks off on the side previously specified (ugh) */
{
goffside = tside;
}
void setlist(void) /* remember that there was an explicit list */
{
tlist = 1;
}
void tickdir(int dir, double val, int explicit) /* remember in/out [expr] */
{
tick_dir = dir;
if (explicit)
ticklen = val;
}
void ticks(void) /* set autoticks after ticks statement */
{
/* was there an explicit "ticks [side] off"? */
if (toffside)
autoticks &= ~toffside;
/* was there an explicit list? (eg "ticks at ..." or "ticks from ...") */
if (tlist) {
if (tside & (BOT|TOP))
autoticks &= ~(BOT|TOP);
if (tside & (LEFT|RIGHT))
autoticks &= ~(LEFT|RIGHT);
}
/* was there a side without a list? (eg "ticks left in") */
if (tside && !tlist) {
if (tick_dir == IN)
autodir |= tside;
if (tside & (BOT|TOP))
autoticks = (autoticks & ~(BOT|TOP)) | (tside & (BOT|TOP));
if (tside & (LEFT|RIGHT))
autoticks = (autoticks & ~(LEFT|RIGHT)) | (tside & (LEFT|RIGHT));
}
tlist = tside = toffside = goffside = 0;
tick_dir = OUT;
}
double modfloor(double f, double t)
{
t = fabs(t);
return floor(f/t) * t;
}
double modceil(double f, double t)
{
t = fabs(t);
return ceil(f/t) * t;
}
double xtmin, xtmax; /* range of ticks */
double ytmin, ytmax;
double xquant, xmult; /* quantization & scale for auto x ticks */
double yquant, ymult;
double lograt = 5;
void do_autoticks(Obj *p) /* make set of ticks for default coord only */
{
double x, xl, xu, q;
if (p == NULL)
return;
fprintf(tfd, "Autoticks:\t# x %g..%g, y %g..%g",
p->pt.x, p->pt1.x, p->pt.y, p->pt1.y);
fprintf(tfd, "; xt %g,%g, yt %g,%g, xq,xm = %g,%g, yq,ym = %g,%g\n",
xtmin, xtmax, ytmin, ytmax, xquant, xmult, yquant, ymult);
if ((autoticks & (BOT|TOP)) && p->pt1.x >= p->pt.x) { /* make x ticks */
q = xquant;
xl = p->pt.x;
xu = p->pt1.x;
if (xl >= xu)
dflt_tick(xl);
else if ((p->log & XFLAG) && xu/xl >= lograt) {
for (x = q; x < xu; x *= 10) {
logtick(x, xl, xu);
if (xu/xl <= 100) {
logtick(2*x, xl, xu);
logtick(5*x, xl, xu);
}
}
} else {
xl = modceil(xtmin - q/100, q);
xu = modfloor(xtmax + q/100, q) + q/2;
for (x = xl; x <= xu; x += q)
dflt_tick(x);
}
tside = autoticks & (BOT|TOP);
ticklist(p, 0);
}
if ((autoticks & (LEFT|RIGHT)) && p->pt1.y >= p->pt.y) { /* make y ticks */
q = yquant;
xl = p->pt.y;
xu = p->pt1.y;
if (xl >= xu)
dflt_tick(xl);
else if ((p->log & YFLAG) && xu/xl >= lograt) {
for (x = q; x < xu; x *= 10) {
logtick(x, xl, xu);
if (xu/xl <= 100) {
logtick(2*x, xl, xu);
logtick(5*x, xl, xu);
}
}
} else {
xl = modceil(ytmin - q/100, q);
xu = modfloor(ytmax + q/100, q) + q/2;
for (x = xl; x <= xu; x += q)
dflt_tick(x);
}
tside = autoticks & (LEFT|RIGHT);
ticklist(p, 0);
}
}
void logtick(double v, double lb, double ub)
{
float slop = 1.0; /* was 1.001 */
if (slop * lb <= v && ub >= slop * v)
dflt_tick(v);
}
Obj *setauto(void) /* compute new min,max, and quant & mult */
{
Obj *p, *q;
if ((q = lookup("lograt",0)) != NULL)
lograt = q->fval;
for (p = objlist; p; p = p->next)
if (p->type == NAME && strcmp(p->name,dflt_coord) == 0)
break;
if (p) {
if ((p->log & XFLAG) && p->pt1.x/p->pt.x >= lograt)
autolog(p, 'x');
else
autoside(p, 'x');
if ((p->log & YFLAG) && p->pt1.y/p->pt.y >= lograt)
autolog(p, 'y');
else
autoside(p, 'y');
}
return p;
}
void autoside(Obj *p, int side)
{
double r, s, d, ub, lb;
if (side == 'x') {
xtmin = lb = p->pt.x;
xtmax = ub = p->pt1.x;
} else {
ytmin = lb = p->pt.y;
ytmax = ub = p->pt1.y;
}
if (ub <= lb)
return; /* cop out on little ranges */
d = ub - lb;
r = s = 1;
while (d * s < 10)
s *= 10;
d *= s;
while (10 * r < d)
r *= 10;
if (r > d/3)
r /= 2;
else if (r <= d/6)
r *= 2;
if (side == 'x') {
xquant = r / s;
} else {
yquant = r / s;
}
}
void autolog(Obj *p, int side)
{
double r, s, t, ub, lb;
int flg;
if (side == 'x') {
xtmin = lb = p->pt.x;
xtmax = ub = p->pt1.x;
flg = p->coord & XFLAG;
} else {
ytmin = lb = p->pt.y;
ytmax = ub = p->pt1.y;
flg = p->coord & YFLAG;
}
for (s = 1; lb * s < 1; s *= 10)
;
lb *= s;
ub *= s;
for (r = 1; 10 * r < lb; r *= 10)
;
for (t = 1; t < ub; t *= 10)
;
if (side == 'x')
xquant = r / s;
else
yquant = r / s;
if (flg)
return;
if (ub / lb < 100) {
if (lb >= 5 * r)
r *= 5;
else if (lb >= 2 * r)
r *= 2;
if (ub * 5 <= t)
t /= 5;
else if (ub * 2 <= t)
t /= 2;
if (side == 'x') {
xtmin = r / s;
xtmax = t / s;
} else {
ytmin = r / s;
ytmax = t / s;
}
}
}
void iterator(double from, double to, int op, double by, char *fmt) /* create an iterator */
{
double x;
/* should validate limits, etc. */
/* punt for now */
dprintf("iterate from %g to %g by %g, op = %c, fmt=%s\n",
from, to, by, op, fmt ? fmt : "");
switch (op) {
case '+':
case ' ':
for (x = from; x <= to + (SLOP-1) * by; x += by)
if (fmt)
savetick(x, tostring(fmt));
else
dflt_tick(x);
break;
case '-':
for (x = from; x >= to; x -= by)
if (fmt)
savetick(x, tostring(fmt));
else
dflt_tick(x);
break;
case '*':
for (x = from; x <= SLOP * to; x *= by)
if (fmt)
savetick(x, tostring(fmt));
else
dflt_tick(x);
break;
case '/':
for (x = from; x >= to; x /= by)
if (fmt)
savetick(x, tostring(fmt));
else
dflt_tick(x);
break;
}
if (fmt)
free(fmt);
}
void ticklist(Obj *p, int explicit) /* fire out the accumulated ticks */
/* 1 => list, 0 => auto */
{
if (p == NULL)
return;
fprintf(tfd, "Ticks_%s:\n\tticklen = %g\n", p->name, ticklen);
print_ticks(TICKS, explicit, p, "ticklen", "");
}
void print_ticks(int type, int explicit, Obj *p, char *lenstr, char *descstr)
{
int i, logflag, inside;
char buf[100];
double tv;
for (i = 0; i < ntick; i++) /* any ticks given explicitly? */
if (tickstr[i] != NULL)
break;
if (i >= ntick && type == TICKS) /* no, so use values */
for (i = 0; i < ntick; i++) {
if (tickval[i] >= 0.0)
sprintf(buf, "%g", tickval[i]);
else
sprintf(buf, "\\-%g", -tickval[i]);
tickstr[i] = tostring(buf);
}
else
for (i = 0; i < ntick; i++) {
if (tickstr[i] != NULL) {
sprintf(buf, tickstr[i], tickval[i]);
free(tickstr[i]);
tickstr[i] = tostring(buf);
}
}
logflag = sidelog(p->log, tside);
for (i = 0; i < ntick; i++) {
tv = tickval[i];
halfrange(p, tside, tv);
if (logflag) {
if (tv <= 0.0)
ERROR "can't take log of tick value %g", tv FATAL;
logit(tv);
}
if (type == GRID)
inside = LEFT|RIGHT|TOP|BOT;
else if (explicit)
inside = (tick_dir == IN) ? tside : 0;
else
inside = autodir;
if (tside & BOT)
maketick(type, p->name, BOT, inside, tv, tickstr[i], lenstr, descstr);
if (tside & TOP)
maketick(type, p->name, TOP, inside, tv, tickstr[i], lenstr, descstr);
if (tside & LEFT)
maketick(type, p->name, LEFT, inside, tv, tickstr[i], lenstr, descstr);
if (tside & RIGHT)
maketick(type, p->name, RIGHT, inside, tv, tickstr[i], lenstr, descstr);
if (tickstr[i]) {
free(tickstr[i]);
tickstr[i] = NULL;
}
}
ntick = 0;
}
void maketick(int type, char *name, int side, int inflag, double val, char *lab, char *lenstr, char *descstr)
{
char *sidestr, *td;
fprintf(tfd, "\tline %s ", descstr);
inflag &= side;
switch (side) {
case BOT:
case 0:
td = inflag ? "up" : "down";
fprintf(tfd, "%s %s from (x_%s(%g),0)", td, lenstr, name, val);
break;
case TOP:
td = inflag ? "down" : "up";
fprintf(tfd, "%s %s from (x_%s(%g),frameht)", td, lenstr, name, val);
break;
case LEFT:
td = inflag ? "right" : "left";
fprintf(tfd, "%s %s from (0,y_%s(%g))", td, lenstr, name, val);
break;
case RIGHT:
td = inflag ? "left" : "right";
fprintf(tfd, "%s %s from (framewid,y_%s(%g))", td, lenstr, name, val);
break;
}
fprintf(tfd, "\n");
if (type == GRID && (side & goffside)) /* wanted no ticks on grid */
return;
sidestr = tick_dir == IN ? "start" : "end";
if (lab != NULL) {
/* BUG: should fix size of lab here */
double wid = strlen(lab)/7.5 + (tick_dir == IN ? 0 : 0.1); /* estimate width at 15 chars/inch */
switch (side) {
case BOT: case 0:
/* can drop "box invis" with new pic */
fprintf(tfd, "\tbox invis \"%s\" ht .25 wid 0 with .n at last line.%s",
lab, sidestr);
break;
case TOP:
fprintf(tfd, "\tbox invis \"%s\" ht .2 wid 0 with .s at last line.%s",
lab, sidestr);
break;
case LEFT:
fprintf(tfd, "\t\"%s \" wid %.2f rjust at last line.%s",
lab, wid, sidestr);
break;
case RIGHT:
fprintf(tfd, "\t\" %s\" wid %.2f ljust at last line.%s",
lab, wid, sidestr);
break;
}
/* BUG: works only if "down x" comes before "at wherever" */
lab_adjust();
fprintf(tfd, "\n");
}
}
Attr *grid_desc = 0;
void griddesc(Attr *a)
{
grid_desc = a;
}
void gridlist(Obj *p)
{
char *framestr;
if ((tside & (BOT|TOP)) || tside == 0)
framestr = "frameht";
else
framestr = "framewid";
fprintf(tfd, "Grid_%s:\n", p->name);
tick_dir = IN;
print_ticks(GRID, 0, p, framestr, desc_str(grid_desc));
if (grid_desc) {
freeattr(grid_desc);
grid_desc = 0;
}
}
char *desc_str(Attr *a) /* convert DOT to "dotted", etc. */
{
static char buf[50], *p;
if (a == NULL)
return p = "";
switch (a->type) {
case DOT: p = "dotted"; break;
case DASH: p = "dashed"; break;
case INVIS: p = "invis"; break;
default: p = "";
}
if (a->fval != 0.0) {
sprintf(buf, "%s %g", p, a->fval);
return buf;
} else
return p;
}
sidelog(int logflag, int side) /* figure out whether to scale a side */
{
if ((logflag & XFLAG) && ((side & (BOT|TOP)) || side == 0))
return 1;
else if ((logflag & YFLAG) && (side & (LEFT|RIGHT)))
return 1;
else
return 0;
}