no longer hidden
[henge/webcc.git] / org / data / fa / f3ff67-f8e9-41fe-9a32-2ced4bbf5b99 / lexer.c
diff --git a/org/data/fa/f3ff67-f8e9-41fe-9a32-2ced4bbf5b99/lexer.c b/org/data/fa/f3ff67-f8e9-41fe-9a32-2ced4bbf5b99/lexer.c
new file mode 100755 (executable)
index 0000000..2252a37
--- /dev/null
@@ -0,0 +1,180 @@
+/*!@file\r
+  \brief   lexical analyzer implementation for APC\r
+  \details The lexer manages two FIFO stacks.  One for maintaining tokens, the\r
+           other for maintaining a list of files to be scanned.  During\r
+           execution, the lexer will return a token from its token queue if any\r
+           are present.  If not, the lexer will will pop an element from its\r
+           file queue to 'scanner' to be tokenized.  If the file queue is empty,\r
+           the lexer will instead call 'parsedir' to traverse the directory tree\r
+           and tokenize the results.  If 'parsedir' does not generate any new\r
+           tokens, we are done.\r
+  \author  Jordan Lavatai\r
+  \date    Aug 2016\r
+  ----------------------------------------------------------------------------*/\r
+/* Standard */\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <errno.h>\r
+/* Posix */\r
+#include <unistd.h>\r
+#include <stdlib.h>\r
+#include <dirent.h>\r
+/* Local */\r
+#include "parser.tab.h"\r
+#ifndef DE_STACKSIZE\r
+#define DE_STACKSIZE 1024\r
+#endif\r
+#ifndef TK_STACKSIZE\r
+#define TK_STACKSIZE 1024\r
+#endif\r
+/* Public */\r
+int  lexer_init(void);\r
+int  lexer(void);\r
+int  lexer_lexfile(const char*);\r
+void lexer_pushtok(int, YYSTYPE);\r
+extern //lexer_lex.rl\r
+int lexer_lex(const char*);\r
+struct dirent* lexer_direntpa[DE_STACKSIZE], **lexer_direntpp;\r
+/* Private */\r
+extern //scanner.c\r
+int scanner_init(void);\r
+extern //scanner.c\r
+int scanner(void);\r
+static inline\r
+int dredge_current_depth(void);\r
+extern //bison\r
+YYSTYPE yylval;\r
+static\r
+struct tok\r
+{ YYSTYPE lval;  //token val\r
+  int     tok_t; //token type\r
+} token_stack[TK_STACKSIZE];\r
+static\r
+union tokp\r
+{ int*        tpt; //token pointer type\r
+  struct tok* tok;\r
+  YYSTYPE*    tvp; //token value pointer\r
+} tks, tkx;\r
+\r
+/* Directory Entity Array/Stack\r
+   Simple array for keeping track of dirents yet to be processed by the scanner.\r
+   If this list is empty and there are no tokens, the lexer is done.\r
+   This array is populated by the scanner as an array, and popped locally by the\r
+   lexer as a stack.\r
+*/\r
+#define DE_STACK    (lexer_direntpa)\r
+#define DE_STACKP   (lexer_direntpp)\r
+#define DE_LEN()    (DE_STACKP - DE_STACK)\r
+#define DE_INIT()   (DE_STACKP = DE_STACK)\r
+#define DE_POP()    (*--DE_STACKP)\r
+\r
+/* Token Stack\r
+   This is a FIFO stack whose pointers are a union of either a pointer to an\r
+   integer, or a pointer to two integers (a struct tok).  This way, integers may\r
+   be added or removed from the stack either singularly (IPUSH/IPOP), or as a\r
+   full token of two integers (PUSH/POP).\r
+   An alignment error will occur if IPOP or IPUSH are used a non-even number of\r
+   times in a sequence!\r
+*/\r
+#define TK_STACK     (token_stack)\r
+#define TK_STACKP    (tks.tok)\r
+#define TK_STACKPI   (tks.tpt)\r
+#define TK_STACKPL   (tks.tvp)\r
+#define TK_STACKX    (tkx.tok)\r
+#define TK_STACKXI   (tkx.tpt)\r
+#define TK_LEN()     (TK_STACKX - TK_STACKP)\r
+#define TK_INIT()    (TK_STACKP = TK_STACKX = TK_STACK)\r
+#define TK_POP()     (*TK_STACKP++)\r
+#define TK_POPI()    (*TK_STACKPI++);\r
+#define TK_POPL()    (*TK_STACKPL++);\r
+#define TK_PUSH(T,L) (*TK_STACKX++ = (struct tok){L,T})\r
+\r
+/* Initializer\r
+   The initializer returns boolean true if an error occurs, which may be handled   with standard errno.\r
+*/\r
+int lexer_init\r
+()\r
+{ TK_INIT();\r
+  DE_INIT();\r
+  return scanner_init();\r
+}\r
+\r
+/* Lexer\r
+   If the token buffer is empty, 'lexer' will initialize the token buffer and\r
+   call 'lexer_scandir'.  If SCAN_ERROR is returned, an error is printed\r
+   before sending a null return to bison.  If 0 tokens are generated, the error\r
+   printing is skipped.  In all other cases, 'yylval' is set, and the token's\r
+   integer representation is returned.\r
+*/\r
+int lexer\r
+#define $($)#$\r
+#define SCAN_ERROR -1\r
+#define TK_EMPTY   (TK_STACKP == TK_STACKX)\r
+#define FAIL(...)                              \\r
+  do {                                         \\r
+    fprintf(stderr,__VA_ARGS__);               \\r
+    goto done;                                 \\r
+  } while (0)\r
+()\r
+{start:\r
+  while (DE_LEN() > 0)    //lex any directory entries in our stack\r
+    if (lexer_lexfile(DE_POP()->d_name) == 0)\r
+      FAIL("Lexer failed to tokenize [%s]\n",(*DE_STACKP)->d_name);\r
+  if (TK_EMPTY)           //if there are no tokens,\r
+    { TK_INIT();            //initialize the token stack back to 0\r
+      switch (scanner())\r
+        { case SCAN_ERROR:    //if an error occurred,\r
+           FAIL("Scanner error\n");\r
+         case 0:             //if the the scanner finds no dirents,\r
+           goto done;        //then we are done\r
+          default:            //if we found some elements to scan,\r
+           goto start;       //start over and lex them\r
+        }\r
+    }\r
+  yylval = TK_POPL();\r
+  return TK_POPI();\r
+ done:\r
+  yylval.val = 0;\r
+  return 0;\r
+}\r
+\r
+\r
+/* Token Receiver\r
+   This receiver takes a struct tok and pushes it to the FIFO stack.\r
+*/\r
+void lexer_pushtok\r
+#define $($)#$ //stringifier\r
+#define ERR_TK "Fatal: Generated over " $(TK_STACKSIZE) " tokens in one pass."\r
+( int tok, YYSTYPE lval )\r
+{ if (TK_LEN() >= TK_STACKSIZE)\r
+    { fprintf(stderr, ERR_TK);\r
+      exit(EXIT_FAILURE);\r
+    }\r
+  TK_PUSH(tok, lval);\r
+  printf("Pushed Token  %i | %i\n", TK_STACK[TK_LEN() - 1].tok_t, TK_STACK[TK_LEN() - 1].lval.val);\r
+}\r
+\r
+/* Lexical analysis of a file\r
+   Strips a filename to its base name, then sends it to lexer_lex\r
+*/\r
+int lexer_lexfile\r
+#define MAX_FNAME 2048\r
+#define HIDDEN_WARNING "%s is hidden and will not be parsed!\n", filename\r
+( const char  *filename\r
+)\r
+{ static char fname[MAX_FNAME];\r
+  char        *last_period = NULL, *iter;\r
+\r
+  if (*filename == '.')\r
+    { fprintf (stderr, HIDDEN_WARNING);\r
+      return 0;\r
+    }\r
+  strncpy(fname,filename,MAX_FNAME);\r
+  last_period = NULL;\r
+  for (iter = fname; *iter; iter++)\r
+    if (*iter == '.')\r
+      last_period = iter;\r
+  if (last_period)\r
+    *last_period = '\0';\r
+  return lexer_lex(fname);\r
+}\r