rm current_open_file
[henge/webcc.git] / src / apc / lexer.c
index 4e0a611..940ee81 100644 (file)
 /* Posix */
 #include <unistd.h>
 #include <stdlib.h>
+#include <limits.h> //realpath, NAME_MAX, PATH_MAX
 #include <dirent.h>
 /* Local */
-//#include "parser.tab.h"
-#ifndef DP_STACKSIZE
-#define DP_STACKSIZE 1024
+#include "parser.tab.h"
+#ifndef DE_STACKSIZE
+#define DE_STACKSIZE 1024
 #endif
 #ifndef TK_STACKSIZE
 #define TK_STACKSIZE 1024
 #endif
 /* Public */
-struct tok
-{ int lval;
-  int tok;
-};
-int            lexer_init(void);
-int            lexer(void);
-inline
-void           lexer_pushtok(int int);
-struct dirent* lexer_direntpa[DP_STACKSIZE];
+int         lexer_init(void);
+int         lexer(void);
+int         lexer_lexfile(const char*);
+void        lexer_pushtok(int, YYSTYPE);
+char const* lexer_get_current_filepath(void);
+struct dirent* lexer_direntpa[DE_STACKSIZE],** lexer_direntpp,** lexer_direntpb;
 /* Private */
+extern //lexer_lex.rl
+int         lexer_lex(const char*);
+extern //scanner.c
+int         scanner_init(void);
+extern //scanner.c
+int         scanner(void);
 static inline
-int scan(void);
-static inline
-int dredge_current_depth(void);
-static
-struct dirent** dps;
+int         dredge_current_depth(void);
+extern //bison
+YYSTYPE     yylval;
 static
-struct tok token_stack[TK_STACKSIZE];
+char const* current_filename;
 static
-union tokp
-{ int*        i;
-  struct tok* t;
-} tks, tkx;
+struct tok
+{ YYSTYPE lval;  //token val
+  int     tok_t; //token type
+} token_stack[TK_STACKSIZE], *tsp, *tsx;
 
 /* Directory Entity Array/Stack
    Simple array for keeping track of dirents yet to be processed by the scanner.
    If this list is empty and there are no tokens, the lexer is done.
+   This array is populated by the scanner as an array, and popped locally by the
+   lexer as a stack, and is popped as a FIFO stack.
 */
-#define DP_STACK    (lexer_direntpa)
-#define DP_STACKP   (dps)
-#define DP_LEN()    (DP_STACKP - DP_STACK)
-#define DP_INIT()   (DP_STACKP = DP_STACK)
-#define DP_POP()    (*--DP_STACKP)
+#define DE_STACK    (lexer_direntpa)
+#define DE_STACKP   (lexer_direntpp)
+#define DE_STACKB   (lexer_direntpb)
+#define DE_LEN()    (DE_STACKP - DE_STACKB)
+#define DE_INIT()   (DE_STACKP = DE_STACKB = DE_STACK)
+#define DE_POP()    (*DE_STACKB++)
 
 /* Token Stack
    This is a FIFO stack whose pointers are a union of either a pointer to an
@@ -70,100 +75,118 @@ union tokp
    An alignment error will occur if IPOP or IPUSH are used a non-even number of
    times in a sequence!
 */
-#define TK_STACK          (token_stack)
-#define TK_STACKP   (tks.t)
-#define TK_STACKPI  (tks.i)
-#define TK_STACKX   (tkx.t)
-#define TK_STACKXI  (tkx.i)
-#define TK_LEN()    (TK_STACKP - TK_STACKX)
-#define TK_INIT()   (TK_STACKP = TK_STACKX = TK_STACK)
-#define TK_POP()    (*TK_STACKP++)
-#define TK_POPI()   (*TK_STACKPI++);
-#define TK_PUSH(T)  (*TKSTACKX++ = T)
-#define TK_PUSHI(I) (*TKSTACKXI++ = (I))
-
-extern //main.c
-const char* cargs['Z'];
-
-extern //scanner.c
-int scanner_init(void);
-extern //scanner.c
-int scanner(struct dirent**);
+#define TK_STACK     (token_stack)
+#define TK_STACKP    (tsp)
+#define TK_STACKX    (tsx)
+#define TK_LEN()     (TK_STACKX - TK_STACKP)
+#define TK_INIT()    (TK_STACKP = TK_STACKX = TK_STACK)
+#define TK_POP()     (*TK_STACKP++)
+#define TK_PUSH(T,L) (*TK_STACKX++ = (struct tok){L,T})
 
 /* Initializer
-   The initializer returns boolean true if an error occurs, which may be handled   with standard errno.
+   The initializer returns boolean true if an error occurs, which may be handled
+   with standard errno.
 */
 int lexer_init
 ()
 { TK_INIT();
-  DP_INIT();
+  DE_INIT();
+  current_filename  = NULL;
   return scanner_init();
 }
 
 /* Lexer
    If the token buffer is empty, 'lexer' will initialize the token buffer and
-   call 'lexer_scandir'.  If #SCANDIR_ERROR is returned, an error is printed
+   call 'lexer_scandir'.  If SCAN_ERROR is returned, an error is printed
    before sending a null return to bison.  If 0 tokens are generated, the error
    printing is skipped.  In all other cases, 'yylval' is set, and the token's
    integer representation is returned.
 */
 int lexer
+#define $($)#$
 #define SCAN_ERROR -1
 #define TK_EMPTY   (TK_STACKP == TK_STACKX)
+#define FAIL(...)                              \
+  do {                                         \
+    fprintf(stderr,__VA_ARGS__);               \
+    goto done;                                 \
+  } while (0)
 ()
-{ if (TK_EMPTY)
-    { switch (parsedir())
-        { case SCAN_ERROR:
-            perror("lexer_scan");
-          case 0:
-            yylval = 0;
-            return 0;
-          default:
-            break;
+{ struct tok token;
+ start:
+  while (DE_LEN() > 0)    //lex any directory entries in our stack
+    if (lexer_lexfile(DE_POP()->d_name) == 0)
+      FAIL("Lexer failed to tokenize [%s]\n",(*DE_STACKB)->d_name);
+  if (TK_EMPTY)           //if there are no tokens,
+    { TK_INIT();            //initialize the token stack back to 0
+      switch (scanner())
+        { case SCAN_ERROR:    //if an error occurred,
+           FAIL("Scanner error\n");
+         case 0:             //if the the scanner finds no dirents,
+           goto done;        //then we are done
+          default:            //if we found some elements to scan,
+           goto start;       //start over and lex them
         }
     }
-  yylval = TK_IPOP();
-  return TK_IPOP();
+  token = TK_POP();
+  yylval = token.lval;
+  return token.tok_t;
+ done:
+  yylval.val = 0;
+  return 0;
 }
 
+
 /* Token Receiver
    This receiver takes a struct tok and pushes it to the FIFO stack.
 */
-inline
 void lexer_pushtok
-#define ERR_TK "Fatal: Generated over " S(TK_STACKSIZE) " tokens in one pass."
-( struct tok token )
-{ if (TK_LEN >= TK_STACKSIZE)
+#define $($)#$ //stringifier
+#define ERR_TK "Fatal: Generated over " $(TK_STACKSIZE) " tokens in one pass."
+( int tok, YYSTYPE lval )
+{ if (TK_LEN() >= TK_STACKSIZE)
     { fprintf(stderr, ERR_TK);
       exit(EXIT_FAILURE);
     }
-  TK_PUSH(token);
+  TK_PUSH(tok, lval);
 }
 
-/* Lexical Analysis
-   Ragel state machine for tokenizing text.
- */
-void lexer_lex
-(const char* str)
-{ struct tok token;
-  token.TOK = 1;
-  token.LVAL = 2;
-  lexer_pushtok(token);
-  printf (str);
-}
+/* Lexical analysis of a file
+   Strips a filename to its base name, then sends it to lexer_lex
+*/
+int lexer_lexfile
+#define HIDDEN_WARNING "%s is hidden and will not be parsed!\n", filename
+( const char  *filename
+)
+{ static char fname[NAME_MAX];
+  char        *last_period = NULL, *iter;
 
-/*  init_file:
-    if (lsp != NULL)
-    while ((c = *lsp++) == *csp)
-    { switch (c)
-    { case DELIM:
-    delimeters_skipped++;
-    default:
-    csp++; //delayed to ensure csp is the start of scannable text
-    break;
+  if (*filename == '.')
+    { fprintf (stderr, HIDDEN_WARNING);
+      return 0;
     }
+  /* Copy the filename and remove its suffix */
+  strncpy(fname,filename,NAME_MAX);
+  last_period = NULL;
+  for (iter = fname; *iter; iter++)  //find the last '.' char
+    if (*iter == '.')
+      last_period = iter;
+  if (last_period)                   //if we found one,
+    *last_period = '\0';             //truncate the string there
+  /* Register the current_filename */
+  current_filename = filename;
+  
+  return lexer_lex(fname);
+}
+
+char const* lexer_get_current_filepath
+()
+{ static char        current_path[PATH_MAX];
+  static char const* last_filename;
+  if ((!last_filename || last_filename != current_filename) &&
+      (realpath(current_filename, current_path) != current_path))
+    { perror("realpath: ");
+      return NULL;
     }
-    last_string = string;
-    scan_text:
-    return scanner_tokenize(csp);
-*/
+  return (const char*)current_path;
+}