Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

psnoise: a noisy postscript syntax checker

25 views
Skip to first unread message

luserXtrog

unread,
Mar 29, 2009, 3:08:16 AM3/29/09
to
/*
psnoise.c
a noisy postscript syntax checker by M. Joshua Ryan

PUBLIC DOMAIN
*/

#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int puff(char *buf, int nbuf);

/* character classes */
#define eq(a,b) (int)a==b
#define within(a,b) strchr(a,b)!=NULL
int israd (int c){return eq('#',c);}
int isdot (int c){return eq('.',c);}
int ise (int c){return within("eE",c);}
int issign (int c){return within("+-",c);}
int isdelim (int c){return within("()<>[]{}/%",c);}
int isregular(int c)
{return c!=EOF && !isspace(c) && !isdelim(c);}
#undef within
#undef eq

typedef struct { int (*fp)(int); int y, n; } test;

/* n.b. this machine has no x+, use xx* */
/* ^[+-]?\d+$ */
test fsm_dec[] = {
/* 0*/ { issign, 1, 1 },
/* 1*/ { isdigit, 2, -1 }, /* [+-]?! ??(\d)?? */
/* 2*/ { isdigit, 2, -1 }, /* [+-]?\d\d* yes! */
};
int acc_dec(int i){ return i==2; } /*acceptable decimal?*/

/* ^\d+[#][a-Z0-9]+$ */
test fsm_rad[] = {
/* 0*/ { isdigit, 1, -1 },
/* 1*/ { isdigit, 1, 2 }, /* \d\d* */
/* 2*/ { israd, 3, -1 }, /* \d\d*[^\d] */
/* 3*/ { isalnum, 4, -1 }, /* \d\d*# */
/* 4*/ { isalnum, 4, -1 }, /* \d\d*#\x\x* yes! */
};
int acc_rad(int i){ return i==4; } /*acceptable radix?*/

/* ^[+-]?(\d+(\.\d*)?)|(\d*\.\d+)([eE][+-]?\d+)?$ */
test fsm_real[] = {
/* 0*/ { issign, 1, 1 },
/* 1*/ { isdigit, 2, 4 }, /* [+-]? */
/* 2*/ { isdigit, 2, 3 }, /* [+-]?\d\d* yes! */
/* 3*/ { isdot, 6, 7 }, /* [+-]?\d\d*[^\d] */
/* 4*/ { isdot, 5, -1 }, /* [+-]?[^\d] */
/* 5*/ { isdigit, 6, -1 }, /* s?\. where s is [+-] */
/* 6*/ { isdigit, 6, 7 }, /* s?(\d\d*)?\.\d* yes! */
/* 7*/ { ise, 8, -1 }, /* s?(\d\d*)?(\.\d*)? */
/* 8*/ { issign, 9, 9 }, /* s?\d*(\.\d*)?[eE] */
/* 9*/ { isdigit, 10, -1 }, /* s?\d*(\.\d*)?[eE][+-]? */
/*10*/ { isdigit, 10, -1 }, /* s?\d*(\.\d*)?[eE]s?\d\d* yes! */
};
/*acceptable real*/
int acc_real(int i){
switch(i) { case 2: case 6: case 10: return 1; }
return 0; }


/*what's the reverse of reverse polish?*/
int czek(char *s, test *fsm, int(*yes)(int)){
int sta = 0;
while(sta!=-1 && *s) {
if (fsm[sta].fp((int)*s))
{ sta=fsm[sta].y; s++; }
else { sta=fsm[sta].n; } }
return yes(sta); }

int grok(char *s, int ns) { /*dig?*/

if (czek(s, fsm_dec, acc_dec )) {
long num;
num = strtol(s,NULL,10);
if((num==LONG_MAX || num==LONG_MIN) && errno==ERANGE) {
fprintf(stderr, "!limitcheck dec %s\n", s);
} else if (num > INT_MAX || num < INT_MIN) {
fprintf(stderr, "!limitcheck dec: %ld\n", num);
} else
printf( "dec: %d\n", (int)num );
return 1; }

else if (czek(s, fsm_rad, acc_rad )) {
long ra,num;
ra = (int)strtol(s,NULL,10);
if(ra>35 || ra<2) {
fprintf(stderr, "!limitcheck radix %s\n", s);
return 1;
}
num = strtol(strchr(s,'#')+1, NULL, (int)ra);
if ((num==LONG_MAX || num==LONG_MIN) && errno==ERANGE) {
fprintf(stderr, "!limitcheck radix %s\n", s);
} else if (num > INT_MAX || num < INT_MIN) {
fprintf(stderr, "!limitcheck rad: %ld\n", num);
} else
printf( "rad: %d\n", (int)num );
return 1; }

else if (czek(s, fsm_real, acc_real)) {
double num;
num = strtod(s,NULL);
if ((num==HUGE_VAL || num==-HUGE_VAL) && errno==ERANGE) {
fprintf(stderr, "!limitcheck real %s\n", s);
} else if (num > FLT_MAX || num < FLT_MIN) {
fprintf(stderr, "!limitcheck real %f\n", num);
} else
printf("real: %f\n", num);
return 1; }

/*we now have either a single delimiter or a bare word*/
else switch (*s) {
case '(': printf("(str\n"); break;
case ')': printf("str)\n"); break;

case '<': printf("<hex: ");
{ int c; char d;
while((c=getchar()), c!='>' && c!=EOF) {
if(isspace(c))continue;
if (isdigit(c)) c-='0';
else if (c >= 'A' && c <= 'F') c-='A';
else if (c >= 'a' && c <= 'f') c-='a';
else printf("!syntaxerror in hexstring: %c\n", c);
d = c << 4;
while(isspace(c=getchar())) 0xF00L;
if (isdigit(c)) c-='0';
else if (c >= 'A' && c <= 'F') c-='A';
else if (c >= 'a' && c <= 'f') c-='a';
else printf("!syntaxerror in hexstring: %c\n", c);
d |= (char)c;
printf("%d ",(int)d);
}
}
printf(">\n");
break;
case '>': printf("!syntaxerror:\n"); break;

case '{': printf("{proc\n"); break;
case '}': printf("proc}\n"); break;

case '%': printf("%%comment:");
while((s[1]=getchar())!='\n') { putchar(s[1]); }
putchar(s[1]);
break;

case '/':
s[1] = (char)getchar();
puff(s+2, ns-2);
if (s[1] == '/') printf("immediate: %s\n", s+2);
else printf("literal: %s\n", s+1);
break;

/*case '[':*/
/*case ']':*/
default: printf("executable: %s\n", s); break; }

return 1; }


int puff(char *buf, int nbuf) {
int c; char *s = buf;
while ( (c=getchar()), isregular(c) ) {
if(s-buf >= nbuf-1) return 0;
*s++ = (char)c; }
*s = (char)0; (void)ungetc(c,stdin);
return 1; }


int toke(char *buf, int nbuf) {
int c,sta = 1; char *s=buf;
while ( (c=getchar()), c!=EOF && isspace(c) ) /*turn turn turn*/;
if (c==EOF) return 0;
*s++ = (char)c; *s = (char)0;
if (!isdelim(c))
sta=puff(s,nbuf-1);
if (sta)
sta=grok(buf,nbuf);
return sta; }


#define NBUF 20
int main(void) { char buf[NBUF] = "";
while (toke(buf,NBUF)) /*twiddle thumbs*/;
return 0; }

/*eof*/

0 new messages