/* sketch.l Copyright (C) 2005,2006,2007 Eugene K. Ressler, Jr. This file is part of Sketch, a small, simple system for making 3d drawings with LaTeX and the PSTricks or TikZ package. Sketch is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Sketch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Sketch; see the file COPYING.txt. If not, see http://www.gnu.org/copyleft */ %{ #include #include #include #include "geometry.h" #include "symbol.h" #include "expr.h" #include "parse.h" #include "y.tab.h" #include "error.h" #include "opts.h" #if defined(_WIN32) && !defined fileno #define fileno(F) _fileno(F) #pragma warning(disable:4102) #endif // undo the safety net in polygon.h so flex scanner can use these library functions #undef malloc #undef realloc #undef free #undef strdup SRC_LINE line; #define MAX_INPUT_DEPTH 10 struct { YY_BUFFER_STATE buffer_state; SRC_LINE line; } input_stack[MAX_INPUT_DEPTH]; int input_stack_ptr = 0; #define INIT_SPECIAL_BUF_SIZE 40 void update_line_number(void) { int i; for (i = 0; yytext[i]; i++) if (yytext[i] == '\n') line.number++; } %} %x inputdirective Identifier [A-Za-z]([A-Za-z0-9_]*[A-Za-z0-9])? WSnotNL [ \t\r] WS [ \t\r\n] %% [%#].* /* comment; do nothing */ {WSnotNL}+ /* white space; do nothing */ "\n" { line.number++; } "["[^\]=]+=[^\]]+"]" { /* [=] */ // elide the brackets yylval.str = safe_malloc(yyleng + 1 - 2); str_slice(yylval.str, yyleng + 1 - 2, yytext, 1, -1); return OPTS_STR; } "language" { return LANGUAGE; } "pstricks" { return PSTRICKS; } "tikz" { return TIKZ; } "latex" { return LaTeX; } "context" { return ConTeXt; } "input"{WS}* { update_line_number(); BEGIN(inputdirective); } "curve" { return CURVE; } "camera" { return CAMERA; } "def" { return DEF; } "dots" { return DOTS; } "frame" { return FRAME; } "global" { return GLOBAL; } "line" { return LINE; } "polygon" { return POLYGON; } "put" { return PUT; } "repeat" { return REPEAT; } "set" { return SET; } "sweep" { return SWEEP; } "then" { return THEN; } "atan2"{WS}*"(" { update_line_number(); return ATAN2; } "cos"{WS}*"(" { update_line_number(); return COS; } "inverse"{WS}*"(" { update_line_number(); return INVERSE; } "picturebox" { return PICTUREBOX; } "perspective"{WS}*"(" { update_line_number(); return PERSPECTIVE; } "project"{WS}*"(" { update_line_number(); return PROJECT; } "rotate"{WS}*"(" { update_line_number(); return ROTATE; } "scale"{WS}*"(" { update_line_number(); return SCALE; } "sin"{WS}*"(" { update_line_number(); return SIN; } "special"{WS}* { char *rtn; int max_rtn_len, delim, i, ch; update_line_number(); max_rtn_len = INIT_SPECIAL_BUF_SIZE - 1; rtn = safe_malloc(max_rtn_len + 1); i = 0; delim = input(); if (delim == EOF) { err(line, "expected special text, found end of file"); } else { while ((ch = input()) != delim && ch != EOF) { if (ch == '\n') ++line.number; if (i == max_rtn_len) { max_rtn_len *= 2; rtn = safe_realloc(rtn, max_rtn_len + 1); } rtn[i++] = ch; } if (ch != delim) err(line, "missing end delimeter '%c' in special", delim); } rtn[i] = '\0'; yylval.str = rtn; return SPECIAL; } "sqrt"{WS}*"(" { update_line_number(); return SQRT; } "translate"{WS}*"(" { update_line_number(); return TRANSLATE; } "unit"{WS}*"(" { update_line_number(); return UNIT; } "view"{WS}*"(" { update_line_number(); return VIEW; } {Identifier} { str_slice(yylval.name, sizeof yylval.name, yytext, 0, sizeof yylval.name); return ID; } "<"{Identifier}">" { str_slice(yylval.name, sizeof yylval.name, yytext, 1, -1); return ANGLE_ID; } "<>" { return EMPTY_ANGLE; } "'"{WS}*"x" { update_line_number(); yylval.index = 0; return TICK; } "'"{WS}*"y" { update_line_number(); yylval.index = 1; return TICK; } "'"{WS}*"z" { update_line_number(); yylval.index = 2; return TICK; } "("{Identifier}")" { str_slice(yylval.name, sizeof yylval.name, yytext, 1, -1); return PAREN_ID; } "["{Identifier}"]" { str_slice(yylval.name, sizeof yylval.name, yytext, 1, -1); return BRACKET_ID; } "["{Identifier}(","{Identifier})+"]" { yylval.name_list = bracket_id_list_to_name_list(yytext); return BRACKET_ID_LIST; } "[["{Identifier}"]]" { str_slice(yylval.name, sizeof yylval.name, yytext, 2, -2); return DBL_BRACKET_ID; } "{"{Identifier}"}" { str_slice(yylval.name, sizeof yylval.name, yytext, 1, -1); return CURLY_ID; } (([0-9]+"."[0-9]*)|("."[0-9]+)|([0-9]+))([eE][-+]?[0-9]+)? { if (sscanf(yytext, FLOAT_SCAN_FMT, &yylval.flt) != 1) { err(line, "numeric constant %s could not be converted (probably out of range)", yytext); yylval.flt = 0; } return NUM; } "("{WS}*{Identifier}{WS}*")" { warn(line, "found parenthesized identifier '%s'; delete space if you meant a point ref", yytext); yyless(1); return '('; } "["{WS}*{Identifier}{WS}*"]" { warn(line, "found id in brackets '%s'; delete space if you meant a vector ref", yytext); yyless(1); return '['; } "{"{WS}*{Identifier}{WS}*"}" { warn(line, "found id in braces '%s'; delete space if you meant a drawable ref", yytext); yyless(1); return '{'; } "[["{WS}*{Identifier}{WS}*"]]" { warn(line, "found id in double-brackets '%s'; delete space if you meant a transform ref", yytext); yyless(1); return '['; } "<"{WS}*{Identifier}{WS}*">" { warn(line, "found id in angle-brackets '%s'; delete space if you meant a tag ref", yytext); yyless(1); return '<'; } [-+*/^|.()\[\]{}=,] { return yytext[0]; } "{"[^}]*"}" { FILE *f; char buf[1024]; int i; if (line.file_name[0] != '/' && line.file_name[0] != '\\') i = str_last_occurance(line.file_name, "/\\"); if (i >= 0) { str_slice(buf, sizeof buf, line.file_name, 0, i + 1); } else { buf[0] = '\0'; } i = strlen(buf); str_slice(&buf[i], sizeof buf - i, yytext, 1, -1); if (input_stack_ptr >= MAX_INPUT_DEPTH) { err(line, "inputs nested too deeply (file '%s' ignored)", buf); } else { f = fopen(buf, "r"); if (f) { yyin = f; input_stack[input_stack_ptr].buffer_state = YY_CURRENT_BUFFER; input_stack[input_stack_ptr].line = line; input_stack_ptr++; yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); line.number = 1; line.file_name = safe_strdup(buf); } else err(line, "can't open input '%s'", buf); } BEGIN(INITIAL); } <> { if (input_stack_ptr == 0) { yyterminate(); } else { yy_delete_buffer(YY_CURRENT_BUFFER); // don't free: refs may still exist for def locs in the symbol table // safe_free(line.file_name); --input_stack_ptr; yy_switch_to_buffer(input_stack[input_stack_ptr].buffer_state); line = input_stack[input_stack_ptr].line; } } . { die(line, "bad char '%c' (%d)\n", yytext[0], (int)yytext[0]); } %% void set_lexer_file(char *file_name, FILE *f) { line.file_name = safe_strdup(file_name); line.number = 1; yyin = f; }