2 \brief lexical analyzer implementation for APC
3 \details The lexer manages two FIFO stacks. One for maintaining tokens, the
4 other for maintaining a list of files to be scanned. During
5 execution, the lexer will return a token from its token queue if any
6 are present. If not, the lexer will will pop an element from its
7 file queue to 'scanner' to be tokenized. If the file queue is empty,
8 the lexer will instead call 'parsedir' to traverse the directory tree
9 and tokenize the results. If 'parsedir' does not generate any new
11 \author Jordan Lavatai
13 ----------------------------------------------------------------------------*/
23 #include "parser.tab.h"
25 #define DE_STACKSIZE 1024
28 #define TK_STACKSIZE 1024
33 int lexer_lex(const char*);
34 void lexer_pushtok(int, int);
35 struct dirent
* lexer_direntpa
[DE_STACKSIZE
];
38 int scanner_init(void);
42 int dredge_current_depth(void);
49 } token_stack
[TK_STACKSIZE
];
58 /* Directory Entity Array/Stack
59 Simple array for keeping track of dirents yet to be processed by the scanner.
60 If this list is empty and there are no tokens, the lexer is done.
61 This array is populated by the scanner as an array, and popped locally by the
64 #define DE_STACK (lexer_direntpa)
65 #define DE_STACKP (dps)
66 #define DE_LEN() (DE_STACKP - DE_STACK)
67 #define DE_INIT() (DE_STACKP = DE_STACK)
68 #define DE_POP() (*--DE_STACKP)
71 This is a FIFO stack whose pointers are a union of either a pointer to an
72 integer, or a pointer to two integers (a struct tok). This way, integers may
73 be added or removed from the stack either singularly (IPUSH/IPOP), or as a
74 full token of two integers (PUSH/POP).
75 An alignment error will occur if IPOP or IPUSH are used a non-even number of
78 #define TK_STACK (token_stack)
79 #define TK_STACKP (tks.t)
80 #define TK_STACKPI (tks.i)
81 #define TK_STACKX (tkx.t)
82 #define TK_STACKXI (tkx.i)
83 #define TK_LEN() (TK_STACKP - TK_STACKX)
84 #define TK_INIT() (TK_STACKP = TK_STACKX = TK_STACK)
85 #define TK_POP() (*TK_STACKP++)
86 #define TK_POPI() (*TK_STACKPI++);
87 #define TK_PUSH(T,L) (*TK_STACKX++ = (struct tok){L,T})
90 The initializer returns boolean true if an error occurs, which may be handled with standard errno.
96 return scanner_init();
100 If the token buffer is empty, 'lexer' will initialize the token buffer and
101 call 'lexer_scandir'. If #SCANDIR_ERROR is returned, an error is printed
102 before sending a null return to bison. If 0 tokens are generated, the error
103 printing is skipped. In all other cases, 'yylval' is set, and the token's
104 integer representation is returned.
107 #define SCAN_ERROR -1
108 #define TK_EMPTY (TK_STACKP == TK_STACKX)
117 yylval
.NUM
= TK_POPI();
122 Ragel state machine for tokenizing text.
126 { lexer_pushtok(1, 2);
133 This receiver takes a struct tok and pushes it to the FIFO stack.
136 #define S(S)#S //stringifier
137 #define ERR_TK "Fatal: Generated over " S(TK_STACKSIZE) " tokens in one pass."
138 ( int tok
, int lval
)
139 { if (TK_LEN() >= TK_STACKSIZE
)
140 { fprintf(stderr
, ERR_TK
);
147 while ((c = *lsp++) == *csp)
150 delimeters_skipped++;
152 csp++; //delayed to ensure csp is the start of scannable text
156 last_string = string;
158 return scanner_tokenize(csp);