a941c9fb069192d705260f6a14da9e0c16c1be08
[oota-llvm.git] / utils / TableGen / FileLexer.l
1 /*===-- FileLexer.l - Scanner for TableGen Files ----------------*- C++ -*-===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines a simple flex scanner for TableGen files.  This is pretty
11 // straight-forward, except for the magic to handle file inclusion.
12 //
13 //===----------------------------------------------------------------------===*/
14
15 %option prefix="File"
16 %option yylineno
17 %option nostdinit
18 %option never-interactive
19 %option batch
20 %option nodefault
21 %option 8bit
22 %option outfile="Lexer.cpp"
23 %option ecs
24 %option noreject
25 %option noyymore
26
27 %x comment
28
29 %{
30 #include "Record.h"
31 typedef std::pair<llvm::Record*, std::vector<llvm::Init*>*> SubClassRefTy;
32 #include "FileParser.h"
33
34 int Fileparse();
35
36 namespace llvm {
37
38 // Global variable recording the location of the include directory
39 std::string IncludeDirectory;
40
41 /// ParseInt - This has to handle the special case of binary numbers 0b0101
42 ///
43 static int ParseInt(const char *Str) {
44   if (Str[0] == '0' && Str[1] == 'b')
45     return strtol(Str+2, 0, 2);
46   return strtol(Str, 0, 0); 
47 }
48
49 static int CommentDepth = 0;
50
51 struct IncludeRec {
52   std::string Filename;
53   FILE *File;
54   unsigned LineNo;
55   YY_BUFFER_STATE Buffer;
56
57   IncludeRec(const std::string &FN, FILE *F)
58     : Filename(FN), File(F), LineNo(0){
59   }
60 };
61
62 static std::vector<IncludeRec> IncludeStack;
63
64 std::ostream &err() {
65   if (IncludeStack.empty())
66     return std::cerr << "At end of input: ";
67
68   for (unsigned i = 0, e = IncludeStack.size()-1; i != e; ++i)
69     std::cerr << "Included from " << IncludeStack[i].Filename << ":"
70               << IncludeStack[i].LineNo << ":\n";
71   return std::cerr << "Parsing " << IncludeStack.back().Filename << ":"
72                    << Filelineno << ": ";
73 }
74
75 /// ParseFile - this function begins the parsing of the specified tablegen file.
76 ///
77 void ParseFile(const std::string &Filename, const std::string & IncludeDir) {
78   FILE *F = stdin;
79   if (Filename != "-") {
80     F = fopen(Filename.c_str(), "r");
81
82     if (F == 0) {
83       std::cerr << "Could not open input file '" + Filename + "'!\n";
84       exit (1);
85     }
86     IncludeStack.push_back(IncludeRec(Filename, F));
87   } else {
88     IncludeStack.push_back(IncludeRec("<stdin>", stdin));
89   }
90
91   // Record the location of the include directory so that the lexer can find
92   // it later.
93   IncludeDirectory = IncludeDir;
94  
95   Filein = F;
96   Filelineno = 1;
97   Fileparse();
98   Filein = stdin;
99 }
100
101 /// HandleInclude - This function is called when an include directive is
102 /// encountered in the input stream...
103 ///
104 static void HandleInclude(const char *Buffer) {
105   unsigned Length = yyleng;
106   assert(Buffer[Length-1] == '"');
107   Buffer += strlen("include ");
108   Length -= strlen("include ");
109   while (*Buffer != '"') {
110     ++Buffer;
111     --Length;
112   }
113   assert(Length >= 2 && "Double quotes not found?");
114   std::string Filename(Buffer+1, Buffer+Length-1);
115   //std::cerr << "Filename = '" << Filename << "'\n";
116
117   // Save the line number and lex buffer of the includer...
118   IncludeStack.back().LineNo = Filelineno;
119   IncludeStack.back().Buffer = YY_CURRENT_BUFFER;
120
121   // Open the new input file...
122   yyin = fopen(Filename.c_str(), "r");
123   if (yyin == 0) {
124     // If we couldn't find the file in the current directory, look for it in
125     // the include directories.
126     //
127     // NOTE: Right now, there is only one directory.  We need to eventually add
128     // support for more.
129     Filename = IncludeDirectory + "/" + Filename;
130     yyin = fopen(Filename.c_str(), "r");
131     if (yyin == 0) {
132       err() << "Could not find include file '" << Filename << "'!\n";
133       abort();
134     }
135   }
136
137   // Add the file to our include stack...
138   IncludeStack.push_back(IncludeRec(Filename, yyin));
139   Filelineno = 1;  // Reset line numbering...
140   //yyrestart(yyin);    // Start lexing the new file...
141
142   yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
143 }
144
145 /// yywrap - This is called when the lexer runs out of input in one of the
146 /// files. Switch back to an includer if an includee has run out of input.
147 ///
148 extern "C"
149 int yywrap() {
150   if (IncludeStack.back().File != stdin)
151     fclose(IncludeStack.back().File);
152   IncludeStack.pop_back();
153   if (IncludeStack.empty()) return 1;  // Top-level file is done.
154
155   // Otherwise, we need to switch back to a file which included the current one.
156   Filelineno = IncludeStack.back().LineNo;  // Restore current line number
157   yy_switch_to_buffer(IncludeStack.back().Buffer);
158   return 0;
159 }
160
161 } // End llvm namespace
162
163 using namespace llvm;
164
165 %}
166
167 Comment      \/\/.*
168
169 Identifier   [a-zA-Z_][0-9a-zA-Z_]*
170 Integer      [-+]?[0-9]+|0x[0-9a-fA-F]+|0b[01]+
171 CodeFragment \[\{([^}]+|\}[^\]])*\}\]
172 StringVal    \"[^"]*\"
173 IncludeStr   include[ \t\n]+\"[^"]*\"
174
175 %%
176
177 {Comment}      { /* Ignore comments */ }
178
179 {IncludeStr}   { HandleInclude(yytext); }
180 {CodeFragment} { Filelval.StrVal = new std::string(yytext+2, yytext+yyleng-2);
181                  return CODEFRAGMENT; }
182
183 int            { return INT; }
184 bit            { return BIT; }
185 bits           { return BITS; }
186 string         { return STRING; }
187 list           { return LIST; }
188 code           { return CODE; }
189 dag            { return DAG; }
190
191 class          { return CLASS; }
192 def            { return DEF; }
193 field          { return FIELD; }
194 let            { return LET; }
195 in             { return IN; }
196
197 {Identifier}   { Filelval.StrVal = new std::string(yytext, yytext+yyleng);
198                  return ID; }
199 ${Identifier}  { Filelval.StrVal = new std::string(yytext+1, yytext+yyleng);
200                  return VARNAME; } 
201
202 {StringVal}    { Filelval.StrVal = new std::string(yytext+1, yytext+yyleng-1);
203                  return STRVAL; }
204
205 {Integer}      { Filelval.IntVal = ParseInt(Filetext); return INTVAL; }
206
207 [ \t\n]+       { /* Ignore whitespace */ }
208
209
210 "/*"                    { BEGIN(comment); CommentDepth++; }
211 <comment>[^*/]*         /* eat anything that's not a '*' or '/' */
212 <comment>"*"+[^*/]*     /* eat up '*'s not followed by '/'s */
213 <comment>"/*"           { ++CommentDepth; }
214 <comment>"/"+[^*]*      /* eat up /'s not followed by *'s */
215 <comment>"*"+"/"        { if (!--CommentDepth) { BEGIN(INITIAL); } }
216 <comment><<EOF>>        { err() << "Unterminated comment!\n"; abort(); }
217
218 .              { return Filetext[0]; }
219
220 %%