4d3ab0a32ee4dee025e5851c4f859ecd387de456
[henge/webcc.git] / src / apc / lexer.c
1 /*!@file
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
10 tokens, we are done.
11 \author Jordan Lavatai
12 \date Aug 2016
13 ----------------------------------------------------------------------------*/
14 /* Standard */
15 #include <stdio.h>
16 #include <string.h>
17 #include <errno.h>
18 /* Posix */
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <dirent.h>
22 /* Local */
23 #include "parser.tab.h"
24 #ifndef DE_STACKSIZE
25 #define DE_STACKSIZE 1024
26 #endif
27 #ifndef TK_STACKSIZE
28 #define TK_STACKSIZE 1024
29 #endif
30 /* Public */
31 int lexer_init(void);
32 int lexer(void);
33 void lexer_pushtok(int, YYSTYPE);
34 extern //ragel
35 int lexer_lex(const char*);
36 struct dirent* lexer_direntpa[DE_STACKSIZE];
37 /* Private */
38 extern //scanner.c
39 int scanner_init(void);
40 extern //scanner.c
41 int scanner(void);
42 static inline
43 int dredge_current_depth(void);
44 extern //bison
45 YYSTYPE yylval;
46 static
47 struct tok
48 { union YYSTYPE val; //token val
49 int tt; //token type
50 } token_stack[TK_STACKSIZE];
51 static
52 union tokp
53 { int* tpt; //token pointer type
54 struct tok* tok;
55 union YYSTYPE* tvp; //token value pointer
56 } tks, tkx;
57 static
58 struct dirent** dps;
59
60 /* Directory Entity Array/Stack
61 Simple array for keeping track of dirents yet to be processed by the scanner.
62 If this list is empty and there are no tokens, the lexer is done.
63 This array is populated by the scanner as an array, and popped locally by the
64 lexer as a stack.
65 */
66 #define DE_STACK (lexer_direntpa)
67 #define DE_STACKP (dps)
68 #define DE_LEN() (DE_STACKP - DE_STACK)
69 #define DE_INIT() (DE_STACKP = DE_STACK)
70 #define DE_POP() (*--DE_STACKP)
71
72 /* Token Stack
73 This is a FIFO stack whose pointers are a union of either a pointer to an
74 integer, or a pointer to two integers (a struct tok). This way, integers may
75 be added or removed from the stack either singularly (IPUSH/IPOP), or as a
76 full token of two integers (PUSH/POP).
77 An alignment error will occur if IPOP or IPUSH are used a non-even number of
78 times in a sequence!
79 */
80 #define TK_STACK (token_stack)
81 #define TK_STACKP (tks.tok)
82 #define TK_STACKPI (tks.tpt)
83 #define TK_STACKPL (tks.tvp)
84 #define TK_STACKX (tkx.tok)
85 #define TK_STACKXI (tkx.tpt)
86 #define TK_LEN() (TK_STACKP - TK_STACKX)
87 #define TK_INIT() (TK_STACKP = TK_STACKX = TK_STACK)
88 #define TK_POP() (*TK_STACKP++)
89 #define TK_POPI() (*TK_STACKPI++);
90 #define TK_POPL() (*TK_STACKPL++);
91 #define TK_PUSH(T,L) (*TK_STACKX++ = (struct tok){L,T})
92
93 /* Initializer
94 The initializer returns boolean true if an error occurs, which may be handled with standard errno.
95 */
96 int lexer_init
97 ()
98 { TK_INIT();
99 DE_INIT();
100 return scanner_init();
101 }
102
103 /* Lexer
104 If the token buffer is empty, 'lexer' will initialize the token buffer and
105 call 'lexer_scandir'. If #SCANDIR_ERROR is returned, an error is printed
106 before sending a null return to bison. If 0 tokens are generated, the error
107 printing is skipped. In all other cases, 'yylval' is set, and the token's
108 integer representation is returned.
109 */
110 int lexer
111 #define SCAN_ERROR -1
112 #define TK_EMPTY (TK_STACKP == TK_STACKX)
113 ()
114 { if (TK_EMPTY)
115 { TK_INIT();
116 if (scanner() == 0)
117 { yylval.val = 0;
118 return 0;
119 }
120 }
121 yylval = TK_POPL();
122 return TK_POPI();
123 }
124
125
126 /* Token Receiver
127 This receiver takes a struct tok and pushes it to the FIFO stack.
128 */
129 void lexer_pushtok
130 #define S(S)#S //stringifier
131 #define ERR_TK "Fatal: Generated over " S(TK_STACKSIZE) " tokens in one pass."
132 ( int tok, YYSTYPE lval )
133 { if (TK_LEN() >= TK_STACKSIZE)
134 { fprintf(stderr, ERR_TK);
135 exit(EXIT_FAILURE);
136 }
137 TK_PUSH(tok, lval);
138 }
139 /* init_file:
140 if (lsp != NULL)
141 while ((c = *lsp++) == *csp)
142 { switch (c)
143 { case DELIM:
144 delimeters_skipped++;
145 default:
146 csp++; //delayed to ensure csp is the start of scannable text
147 break;
148 }
149 }
150 last_string = string;
151 scan_text:
152 return scanner_tokenize(csp);
153 */