aboutsummaryrefslogtreecommitdiff
path: root/shared/common/lex.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared/common/lex.c')
-rw-r--r--shared/common/lex.c272
1 files changed, 272 insertions, 0 deletions
diff --git a/shared/common/lex.c b/shared/common/lex.c
new file mode 100644
index 0000000..e9fd574
--- /dev/null
+++ b/shared/common/lex.c
@@ -0,0 +1,272 @@
+/* Copyright (c) 1997-2004 Miller Puckette, krzYszcz, and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef MIXED_STANDALONE
+#include "unstable/standalone.h"
+#else
+#include "m_pd.h"
+#endif
+#include "common/lex.h"
+
+static int lex_nextbyte(t_lex *lx, unsigned char *buf)
+{
+ int ich;
+ if (lx->l_fp)
+ {
+ if ((ich = fgetc(lx->l_fp)) == EOF)
+ return (0);
+ }
+ else if (lx->l_buf)
+ {
+ if (lx->l_bufndx < lx->l_bufsize)
+ ich = lx->l_buf[lx->l_bufndx++];
+ else
+ return (0);
+ }
+ else return (0);
+ if (ich)
+ {
+ *buf = (unsigned char)ich;
+ return (1);
+ }
+ else
+ {
+ lx->l_errbinary = 1;
+ return (0);
+ }
+}
+
+static void lex_ungetbyte(t_lex *lx, unsigned char ch)
+{
+ if (lx->l_fp)
+ {
+ ungetc(ch, lx->l_fp);
+ }
+ else if (lx->l_buf)
+ {
+ if (lx->l_bufndx > 0)
+ lx->l_buf[--lx->l_bufndx] = ch;
+ }
+}
+
+/* single pass of binbuf_text(), optionally int-preserving version */
+int lex_nextatom(t_lex *lx, t_atom *ap)
+{
+ char buf[1001], *bufp, *ebuf = buf + 1000;
+ int ready;
+ unsigned char ch;
+ ap->a_type = A_NULL;
+ while ((ready = lex_nextbyte(lx, &ch)) &&
+ (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'));
+ if (!ready)
+ {
+ /* ??? */
+ if (lx->l_lasttype == A_SEMI)
+ return (0);
+ else
+ ap->a_type = A_SEMI;
+ }
+ else if (ch == ';')
+ ap->a_type = A_SEMI;
+ else if (ch == ',')
+ ap->a_type = A_COMMA;
+ else
+ {
+ int floatstate = 0, slash = 0, lastslash = 0, firstslash = (ch == '\\');
+ bufp = buf;
+ do
+ {
+ *bufp = ch;
+ lastslash = slash;
+ slash = (ch == '\\');
+
+ if (floatstate >= 0)
+ {
+ int digit = (ch >= '0' && ch <= '9'),
+ dot = (ch == '.'), minus = (ch == '-'),
+ plusminus = (minus || (ch == '+')),
+ expon = (ch == 'e' || ch == 'E');
+ if (floatstate == 0) /* beginning */
+ {
+ if (minus) floatstate = 1;
+ else if (digit) floatstate = 2;
+ else if (dot) floatstate = 3;
+ else floatstate = -1;
+ }
+ else if (floatstate == 1) /* got minus */
+ {
+ if (digit) floatstate = 2;
+ else if (dot) floatstate = 3;
+ else floatstate = -1;
+ }
+ else if (floatstate == 2) /* got digits */
+ {
+ if (dot) floatstate = 4;
+ else if (expon) floatstate = 6;
+ else if (!digit) floatstate = -1;
+ }
+ else if (floatstate == 3) /* got '.' without digits */
+ {
+ if (digit) floatstate = 5;
+ else floatstate = -1;
+ }
+ else if (floatstate == 4) /* got '.' after digits */
+ {
+ if (digit) floatstate = 5;
+ else if (expon) floatstate = 6;
+ else floatstate = -1;
+ }
+ else if (floatstate == 5) /* got digits after . */
+ {
+ if (expon) floatstate = 6;
+ else if (!digit) floatstate = -1;
+ }
+ else if (floatstate == 6) /* got 'e' */
+ {
+ if (plusminus) floatstate = 7;
+ else if (digit) floatstate = 8;
+ else floatstate = -1;
+ }
+ else if (floatstate == 7) /* got plus or minus */
+ {
+ if (digit) floatstate = 8;
+ else floatstate = -1;
+ }
+ else if (floatstate == 8) /* got digits */
+ {
+ if (!digit) floatstate = -1;
+ }
+ }
+ if (!slash) bufp++;
+ }
+ while ((ready = lex_nextbyte(lx, &ch)) && bufp != ebuf
+ && (slash || (ch != ' ' && ch != '\n' && ch != '\r'
+ && ch != '\t' && ch != ',' && ch != ';')));
+ if (ready && (ch == ',' || ch == ';'))
+ lex_ungetbyte(lx, ch);
+ *bufp = 0;
+#if 0
+ fprintf(stderr, "buf %s\n", buf);
+#endif
+ if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9' && !firstslash)
+ {
+ for (bufp = buf+2; *bufp; bufp++)
+ {
+ if (*bufp < '0' || *bufp > '9')
+ {
+ ap->a_type = A_DOLLSYM;
+ ap->a_w.w_symbol = gensym(buf+1);
+ break;
+ }
+ }
+ if (ap->a_type == A_NULL)
+ {
+ ap->a_type = A_DOLLAR;
+ ap->a_w.w_index = atoi(buf+1);
+ }
+ }
+ else if (floatstate == 2)
+ {
+ if (lx->l_inttype == A_FLOAT)
+ {
+ ap->a_type = A_FLOAT;
+ ap->a_w.w_float = (float)atof(buf);
+ }
+ else
+ {
+ ap->a_type = lx->l_inttype;
+ ap->a_w.w_index = atoi(buf);
+ }
+ }
+ else if (floatstate == 4 || floatstate == 5 || floatstate == 8)
+ {
+ ap->a_type = A_FLOAT;
+ ap->a_w.w_float = (float)atof(buf);
+ }
+ else
+ {
+ ap->a_type = A_SYMBOL;
+ ap->a_w.w_symbol = gensym(buf);
+ }
+ }
+ lx->l_lasttype = ap->a_type;
+ return (1);
+}
+
+void lex_atomstring(t_atom *ap, char *buf, int bufsize, t_atomtype inttype)
+{
+ char *sp, *bp, *ep;
+ switch(ap->a_type)
+ {
+ case A_SEMI:
+ strcpy(buf, ";"); break;
+ case A_COMMA:
+ strcpy(buf, ","); break;
+ case A_FLOAT:
+ sprintf(buf, "%#f", ap->a_w.w_float);
+ ep = buf + strlen(buf) - 1;
+ while (ep > buf && *ep == '0') *ep-- = 0;
+ break;
+ case A_SYMBOL:
+ sp = ap->a_w.w_symbol->s_name;
+ bp = buf;
+ ep = buf + (bufsize-5);
+ while (bp < ep && *sp)
+ {
+ if (*sp == ';' || *sp == ',' || *sp == '\\' ||
+ (*sp == '$' && bp == buf && sp[1] >= '0' && sp[1] <= '9'))
+ *bp++ = '\\';
+ if ((unsigned char)*sp < 127)
+ *bp++ = *sp++;
+ else
+ /* FIXME this is temporary -- codepage horror */
+ sprintf(bp, "\\%.3o", (unsigned char)*sp++), bp += 4;
+ }
+ if (*sp) *bp++ = '*';
+ *bp = 0;
+ break;
+ case A_DOLLAR:
+ sprintf(buf, "$%d", ap->a_w.w_index);
+ break;
+ case A_DOLLSYM:
+ sprintf(buf, "$%s", ap->a_w.w_symbol->s_name);
+ break;
+ default:
+ if (ap->a_type == inttype)
+ sprintf(buf, "%d", ap->a_w.w_index);
+ else
+ {
+#ifdef MIXED_STANDALONE
+ fprintf(stderr, "BUG (lex): bad atom type\n");
+#else
+ bug("lex_atomstring (bad atom type)");
+#endif
+ strcpy(buf, "???");
+ }
+ }
+}
+
+int lex_isbinary(t_lex *lx)
+{
+ return (lx->l_errbinary);
+}
+
+void lex_free(t_lex *lx)
+{
+ freebytes(lx, sizeof(*lx));
+}
+
+t_lex *lex_new(FILE *fp, t_atomtype inttype)
+{
+ t_lex *lx = (t_lex *)getbytes(sizeof(*lx));
+ lx->l_fp = fp;
+ lx->l_buf = 0; /* FIXME */
+ lx->l_inttype = inttype;
+ lx->l_lasttype = A_SEMI;
+ lx->l_errbinary = 0;
+ return (lx);
+}