+++ /dev/null
-/*!@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