%{ /* lexer.l: the nawm tokenizer */ /* Copyright (C) 1999 by the Massachusetts Institute of Technology. * * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" * without express or implied warranty. */ #include #include #include #include #include "nawm.h" #include "lang.h" #include "parser.h" int nawm_input(char *buf, int bufsize); void *search_keys(char *name, int *kind); #undef YY_INPUT #define YY_INPUT(buf, result, size) { result = nawm_input(buf, size); } #undef yywrap #define yywrap() 1 char *process_string(char *str); varbinding *mkvarbinding(char *, int, void *); extern int yyparse(void); extern dtype rettype; extern Window root; extern Display *dpy; int kind, lineno; typedef struct _lexscope { struct _lexscope *parent; int numvars; varbinding *vars; dtype *vtypes; } lexscope; static lexscope *scopestack; %} %% include { return INCLUDE; } option { return OPTION; } begin { return BEGIN_; } end { return END; } command { return COMMAND; } function { return FUNCTION; } mode { return MODE; } int { yylval.i = T_INT; return DTYPE; } string { yylval.i = T_STR; return DTYPE; } window { yylval.i = T_WIN; return DTYPE; } key { return KEYPRESS; } keypress { return KEYPRESS; } keyrelease { return KEYRELEASE; } button { return BUTTONPRESS; } buttonpress { return BUTTONPRESS; } buttonrelease { return BUTTONRELEASE; } motion { return MOTION; } enter { return ENTER; } leave { return LEAVE; } if { return IF; } else { return ELSE; } for { return FOR; } in { return IN; } while { return WHILE; } do { return DO; } break { return BREAK; } continue { return CONTINUE; } return { return RETURN; } del { return DEL; } [A-Za-z_][A-Za-z_0-9]* { yylval.n = lookup(yytext, &kind, 0); if (yylval.n) return kind; else { yylval.s = xstrdup(yytext); return SYM; } } [0-9]+ { yylval.i = atoi(yytext); return NUM; } \"([^"\\]|\\.)*\" { yylval.s = process_string(yytext); return STR; } "+" { yylval.i = PLUS; return ADDOP; } "-" { yylval.i = MINUS; return ADDOP; } "*" { yylval.i = TIMES; return MULTOP; } "/" { yylval.i = DIVIDE; return MULTOP; } "%" { yylval.i = REMAINDER; return MULTOP; } "==" { yylval.i = EQUAL; return COMPOP; } "!=" { yylval.i = NOTEQUAL; return COMPOP; } "<=" { yylval.i = LESSEQUAL; return COMPOP; } "<" { yylval.i = LESS; return COMPOP; } ">=" { yylval.i = GREATEREQUAL; return COMPOP; } ">" { yylval.i = GREATER; return COMPOP; } "=" { yylval.i = ASSIGN; return ASSIGNOP; } "&&" { yylval.i = AND; return BOOLOP; } "||" { yylval.i = OR; return BOOLOP; } "!" { yylval.i = NOT; return UNOP; } "(" { return '('; } ")" { return ')'; } "[" { return '['; } "]" { return ']'; } "{" { return '{'; } "}" { return '}'; } "." { return '.'; } "," { return ','; } ";" { return ';'; } [ \t]* { ; } #.*$ { ; } \n { lineno++; } . { die("Bad character `%c' in input at line %d.", *yytext, lineno); } %% char *pstr; extern FILE *yyin; void initlex(void) { scopestack = NULL; pushlexscope(0); } void parse_file(char *name) { lineno = 1; rettype = -1; if (!strcmp(name, "-")) yyin = stdin; else yyin = fopen(name, "r"); if (!yyin) { die("Can't open file `%s'\n", name); return; } pstr = NULL; yyparse(); if (strcmp(name, "-")) fclose(yyin); lineno = 0; } void parse_string(char *s) { lineno = 0; rettype = -1; pstr = s; yyparse(); lineno = 0; } int nawm_input(char *buf, int bufsize) { int bytesread; if (pstr) { if (*pstr) { buf[bufsize - 1] = '\0'; strncpy(buf, pstr, bufsize - 1); bytesread = strlen(buf); pstr += bytesread; } else bytesread = 0; } else bytesread = fread(buf, 1, bufsize, yyin); return bytesread; } char *process_string(char *str) { char *newstr, *s, *d; int len = strlen(str) - 2; newstr = xmalloc(len + 1); for (s = str + 1, d = newstr; s < str + len + 1; s++, d++) { if (*s == '\\') { switch (*++s) { case '\'': case '"': case '?': case '\\': *d = *s; break; case 'a': *d = '\a'; break; case 'b': *d = '\b'; break; case 'f': *d = '\f'; break; case 'n': *d = '\n'; break; case 'r': *d = '\r'; break; case 't': *d = '\t'; break; case 'v': *d = '\v'; break; case 'x': #define xdigit(x) ( isdigit(x) ? x - '0' : x - 'a' + 10 ) if (isxdigit(s[1]) && isxdigit(s[2])) *d = xdigit(*++s) * 16 + xdigit(*++s); else die("bad hex constant in \"%s\"", str); break; default: #define isodigit(x) ( isdigit(x) && x != '8' && x != '9' ) if (!isodigit(s[0]) || !isodigit(s[1]) || !isodigit(s[2])) die("bad escape in \"%s\"", str); else *d = xdigit(*++s) * 64 + xdigit(*++s) * 8 + xdigit(*++s); break; } } else *d = *s; } *d = '\0'; return newstr; } varbinding *mkvarbinding(char *name, int type, void *data) { varbinding *b = xmalloc(sizeof(varbinding)); b->name = name; b->type = type; b->data = data; b->next = NULL; return b; } void pushlexscope(int nestable) { lexscope *tmp; tmp = xmalloc(sizeof(lexscope)); tmp->numvars = nestable ? 0 : -1; tmp->vars = NULL; tmp->vtypes = malloc(0); tmp->parent = scopestack; scopestack = tmp; } dtype *getscopevartypes(void) { return scopestack->vtypes; } int getscopenumvars(void) { return scopestack->numvars; } void poplexscope(void) { lexscope *tmp = scopestack; varbinding *v, *vtmp; scopestack = scopestack->parent; free(tmp->vtypes); for (v = tmp->vars; v; v = vtmp) { free(v->name); vtmp = v->next; free(v); } free(tmp); } variable *mkvar(dtype type) { variable *v = xmalloc(sizeof(variable)); v->type = type; if (scopestack->numvars == -1) { v->slot = -1; v->data = initial_value(type); } else { scopestack->vtypes = xrealloc(scopestack->vtypes, (scopestack->numvars + 1) * sizeof(dtype)); scopestack->vtypes[scopestack->numvars] = type; v->slot = scopestack->numvars++; } return v; } void define(int type, char *name, void *data) { varbinding *var; int tmp; if (!scopestack) die("Definition not allowed here.\n"); if (search_builtins(name, &tmp)) die("Attempted to redefine builtin `%s'\n", name); for (var = scopestack->vars; var; var = var->next) { if (!strcmp(var->name, name)) die("Attempted to redefine %s `%s'.", var->type == VAR ? "variable" : var->type == FUN ? "function" : "command", name); } var = mkvarbinding(xstrdup(name), type, data); var->next = scopestack->vars; scopestack->vars = var; } void *lookup(char *name, int *type, int norecurse) { lexscope *scope; varbinding *b; void *ans; ans = search_builtins(name, type); if (ans) return ans; for (scope = scopestack; scope; scope = scope->parent) { for (b = scope->vars; b; b = b->next) { if (!strcmp(b->name, name)) { *type = b->type; return b->data; } } if (norecurse) break; } return NULL; } char *nameof(void *data) { lexscope *scope; char *ans; varbinding *b; ans = nameof_builtin(data); if (ans) return ans; for (scope = scopestack; scope; scope = scope->parent) { for (b = scope->vars; b; b = b->next) { if (b->data == data) return b->name; } } return "[unknown symbol]"; }