/* Posix */
#include <unistd.h>
#include <stdlib.h>
+#include <limits.h> //realpath, NAME_MAX, PATH_MAX
#include <dirent.h>
/* Local */
#include "parser.tab.h"
#define TK_STACKSIZE 1024
#endif
/* Public */
-int lexer_init(void);
-int lexer(void);
-int lexer_lex(const char*);
-void lexer_pushtok(int, int);
-struct dirent* lexer_direntpa[DE_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;
/* Private */
+extern //lexer_lex.rl
+int lexer_lex(const char*);
extern //scanner.c
-int scanner_init(void);
+int scanner_init(void);
extern //scanner.c
-int scanner(void);
+int scanner(void);
static inline
-int dredge_current_depth(void);
+int dredge_current_depth(void);
extern //bison
-YYSTYPE yylval;
+YYSTYPE yylval;
static
-struct tok
-{ int lval;
- int tok;
-} token_stack[TK_STACKSIZE];
-static
-union tokp
-{ int* i;
- struct tok* t;
-} tks, tkx;
+char const* current_filename;
static
-struct dirent** dps;
+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.
lexer as a stack.
*/
#define DE_STACK (lexer_direntpa)
-#define DE_STACKP (dps)
+#define DE_STACKP (lexer_direntpp)
#define DE_LEN() (DE_STACKP - DE_STACK)
#define DE_INIT() (DE_STACKP = DE_STACK)
#define DE_POP() (*--DE_STACKP)
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_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_POPI() (*TK_STACKPI++);
#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
()
/* 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)
- { TK_INIT();
- if (scanner() == 0)
- { yylval.val = 0;
- return 0;
+{ 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_STACKP)->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.val = TK_POPI();
- return TK_POPI();
-}
-
-/* Lexical Analysis
- Ragel state machine for tokenizing text.
-*/
-int lexer_lex
-(const char* str)
-{ lexer_pushtok(1, 2);
- printf (str);
- return 1;
+ token = TK_POP();
+ yylval = token.lval;
+ return token.tok_t;
+ done:
+ yylval.val = 0;
+ return 0;
}
This receiver takes a struct tok and pushes it to the FIFO stack.
*/
void lexer_pushtok
-#define S(S)#S //stringifier
-#define ERR_TK "Fatal: Generated over " S(TK_STACKSIZE) " tokens in one pass."
-( int tok, int lval )
+#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(tok, lval);
}
-/* 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;
+
+/* 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;
+
+ 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;
+}