/*!@file \brief lexical analyzer implementation for APC \details this lexer scans a root directory given from the command line for subdirectories and files structured for the APC grammar. \author Jordan Lavatai \date Aug 2016 ----------------------------------------------------------------------------*/ //stdc #include #include #include //posix #include #include //bison #include "fileparser.tab.h" #define TOKEN_BUF_SIZE 1024 #define DIRP_STACK_SIZE 512 int lexer_init(void); int lexer(void); static int lexer_scan(void); static int token_buf[TOKEN_BUF_SIZE], *tbp, *tbx; static DIR* dirp_stack[DIRP_STACK_SIZE], *dsp; /* Initialize pointers */ int lexer_init() { tbp = tbx = token_buf; dsp = dirp_stack; return 0; } /* Returns a token identifier and sets yylval */ int lexer() { if (lexer_scan() == 0) return 0; yylval = *tbp++; return *tbp++; } /* Scanner Scans a filename from its alphabetically ordered list of file elements and tokenizes the result. If the file list is empty, then the stack of directory elements will be popped and processed as they are encountered. Returns the number of tokens generated. */ #define MAX_ENTITIES 256 static int lexer_scan() { static struct dirent* entity; static struct dirent* files[MAX_ENTITIES]; static struct dirent* dirs = files + MAX_ENTITIES - 1; static int num_files = 0; static int num_dirs = 0; //sort out files and directories, grow directories from bottom up while ((entity = readdir(dirp)) != NULL) { switch (entity->d_type) { case DT_LNK: case DT_REG: files[num_files++] = entity; break; case DT_DIR: *(dirs - num_dirs++) = entity; break; case DT_UNKNOWN: default: printf("Ignoring unknown file: %s\n", entity->d_name); break; } } if (errno) perror("readdir"); qsort(&files[0], num_files, sizeof struct dirent*, qalpha); num_ents = scandirat(dirfd, ".", &namelist, scanfilter, scancompar); if (num_ents < 0) { perror("scandirat"); return -1; } //process files //recurse into directories }