1 // gensyscalls.cpp 2 // 3 // Copyright (c) 2004, Ingo Weinhold <bonefish@cs.tu-berlin.de> 4 // All rights reserved. Distributed under the terms of the OpenBeOS License. 5 6 #include <fcntl.h> 7 #include <fstream> 8 #include <list> 9 #include <stack> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string> 13 #include <vector> 14 15 // usage 16 const char *kUsage = 17 "Usage: gensyscalls <header> <dispatcher template> <calls> <dispatcher>\n" 18 "\n" 19 " <header> - Input: The preprocessed header file with the\n" 20 " syscall prototypes.\n" 21 " <dispatcher template> - Input: A template used to generate the syscall\n" 22 " dispatcher source file.\n" 23 " <calls> - Output: The assembly source file implementing the\n" 24 " actual syscalls." 25 " <dispatcher> - Output: The syscall dispatcher source file.\n"; 26 27 // print_usage 28 static 29 void 30 print_usage(bool error) 31 { 32 fprintf((error ? stderr : stdout), kUsage); 33 } 34 35 // Type 36 struct Type { 37 Type(const char *type) : type(type) {} 38 Type(const string &type) : type(type) {} 39 40 string type; 41 }; 42 43 // Function 44 class Function { 45 public: 46 Function() : fReturnType("") {} 47 48 void SetName(const string &name) 49 { 50 fName = name; 51 } 52 53 const string &GetName() const 54 { 55 return fName; 56 } 57 58 void AddParameter(const Type &type) 59 { 60 fParameters.push_back(type); 61 } 62 63 int CountParameters() const 64 { 65 return fParameters.size(); 66 } 67 68 const Type &ParameterAt(int index) const 69 { 70 return fParameters[index]; 71 } 72 73 void SetReturnType(const Type &type) 74 { 75 fReturnType = type; 76 } 77 78 const Type &GetReturnType() const 79 { 80 return fReturnType; 81 } 82 83 private: 84 string fName; 85 vector<Type> fParameters; 86 Type fReturnType; 87 }; 88 89 // Exception 90 struct Exception : exception { 91 Exception() 92 : fMessage() 93 { 94 } 95 96 Exception(const string &message) 97 : fMessage(message) 98 { 99 } 100 101 virtual ~Exception() {} 102 103 virtual const char *what() const 104 { 105 return fMessage.c_str(); 106 } 107 108 private: 109 string fMessage; 110 }; 111 112 // EOFException 113 struct EOFException : public Exception { 114 EOFException() {} 115 EOFException(const string &message) : Exception(message) {} 116 virtual ~EOFException() {} 117 }; 118 119 // IOException 120 struct IOException : public Exception { 121 IOException() {} 122 IOException(const string &message) : Exception(message) {} 123 virtual ~IOException() {} 124 }; 125 126 // ParseException 127 struct ParseException : public Exception { 128 ParseException() {} 129 ParseException(const string &message) : Exception(message) {} 130 virtual ~ParseException() {} 131 }; 132 133 134 // Tokenizer 135 class Tokenizer { 136 public: 137 Tokenizer(istream &input) 138 : fInput(input), 139 fHasCurrent(false) 140 { 141 } 142 143 string GetCurrentToken() 144 { 145 if (!fHasCurrent) 146 throw Exception("GetCurrentToken(): No current token!"); 147 return fTokens.front(); 148 } 149 150 string GetNextToken() 151 { 152 return GetNextToken(NULL); 153 } 154 155 string GetNextToken(stack<string> &skippedTokens) 156 { 157 return GetNextToken(&skippedTokens); 158 } 159 160 string GetNextToken(stack<string> *skippedTokens) 161 { 162 if (fHasCurrent) { 163 fTokens.pop_front(); 164 fHasCurrent = false; 165 } 166 while (fTokens.empty()) 167 _ReadLine(); 168 fHasCurrent = true; 169 if (skippedTokens) 170 skippedTokens->push(fTokens.front()); 171 printf("next token: `%s'\n", fTokens.front().c_str()); 172 return fTokens.front(); 173 } 174 175 void ExpectToken(const string &expectedToken) 176 { 177 string token = GetCurrentToken(); 178 if (expectedToken != token) { 179 throw ParseException(string("Unexpected token `") + token 180 + "'. Expected was `" + expectedToken + "'."); 181 } 182 } 183 184 void ExpectNextToken(const string &expectedToken) 185 { 186 GetNextToken(); 187 ExpectToken(expectedToken); 188 } 189 190 bool CheckToken(const string &expectedToken) 191 { 192 string token = GetCurrentToken(); 193 return (expectedToken == token); 194 } 195 196 bool CheckNextToken(const string &expectedToken) 197 { 198 GetNextToken(); 199 bool result = CheckToken(expectedToken); 200 if (!result) 201 PutCurrentToken(); 202 return result; 203 } 204 205 void PutCurrentToken() 206 { 207 if (!fHasCurrent) 208 throw Exception("GetCurrentToken(): No current token!"); 209 fHasCurrent = false; 210 } 211 212 void PutToken(string token) 213 { 214 if (fHasCurrent) { 215 fTokens.pop_front(); 216 fHasCurrent = false; 217 } 218 fTokens.push_front(token); 219 } 220 221 void PutTokens(stack<string> &tokens) 222 { 223 if (fHasCurrent) { 224 fTokens.pop_front(); 225 fHasCurrent = false; 226 } 227 while (!tokens.empty()) { 228 fTokens.push_front(tokens.top()); 229 tokens.pop(); 230 } 231 } 232 233 private: 234 void _ReadLine() 235 { 236 // read the line 237 char buffer[10240]; 238 if (!fInput.getline(buffer, sizeof(buffer))) 239 throw EOFException("Unexpected end of input."); 240 // parse it 241 int len = strlen(buffer); 242 int tokenStart = 0; 243 for (int i = 0; i < len; i++) { 244 char c = buffer[i]; 245 if (isspace(c)) { 246 if (tokenStart < i) 247 fTokens.push_back(string(buffer + tokenStart, buffer + i)); 248 tokenStart = i + 1; 249 continue; 250 } 251 switch (buffer[i]) { 252 case '#': 253 case '(': 254 case ')': 255 case '*': 256 case '&': 257 case '[': 258 case ']': 259 case ';': 260 case ',': 261 if (tokenStart < i) { 262 fTokens.push_back(string(buffer + tokenStart, 263 buffer + i)); 264 } 265 fTokens.push_back(string(buffer + i, buffer + i + 1)); 266 tokenStart = i + 1; 267 break; 268 } 269 } 270 if (tokenStart < len) 271 fTokens.push_back(string(buffer + tokenStart, buffer + len)); 272 } 273 274 private: 275 istream &fInput; 276 list<string> fTokens; 277 bool fHasCurrent; 278 }; 279 280 281 // Main 282 class Main { 283 public: 284 285 int Run(int argc, char **argv) 286 { 287 // parse parameters 288 if (argc >= 2 289 && (string(argv[1]) == "-h" || string(argv[1]) == "--help")) { 290 print_usage(false); 291 return 0; 292 } 293 if (argc != 5) { 294 print_usage(true); 295 return 1; 296 } 297 // fDispatcherTemplateFile = argv[2]; 298 // fCallsFile = argv[3]; 299 // fDispatcherFile = argv[4]; 300 // open the files 301 fHeaderFile.open(argv[1], ifstream::in); 302 if (!fHeaderFile.is_open()) 303 throw new IOException(string("Failed to open `") + argv[1] + "'."); 304 // parse the syscalls 305 vector<Function> syscalls; 306 _ParseSyscalls(syscalls); 307 for (int i = 0; i < (int)syscalls.size(); i++) { 308 const Function &syscall = syscalls[i]; 309 printf("syscall: `%s'\n", syscall.GetName().c_str()); 310 for (int k = 0; k < (int)syscall.CountParameters(); k++) 311 printf(" arg: `%s'\n", syscall.ParameterAt(k).type.c_str()); 312 printf(" return type: `%s'\n", 313 syscall.GetReturnType().type.c_str()); 314 315 } 316 printf("Found %lu syscalls.\n", syscalls.size()); 317 return 0; 318 } 319 320 321 private: 322 void _ParseSyscalls(vector<Function> &syscalls) 323 { 324 Tokenizer tokenizer(fHeaderFile); 325 // find "#pragma syscalls begin" 326 while (true) { 327 while (tokenizer.GetNextToken() != "#"); 328 stack<string> skippedTokens; 329 if (tokenizer.GetNextToken(skippedTokens) == "pragma" 330 && tokenizer.GetNextToken(skippedTokens) == "syscalls" 331 && tokenizer.GetNextToken(skippedTokens) == "begin") { 332 break; 333 } 334 tokenizer.PutTokens(skippedTokens); 335 } 336 // parse the functions 337 while (!tokenizer.CheckNextToken("#")) { 338 Function syscall; 339 _ParseSyscall(tokenizer, syscall); 340 syscalls.push_back(syscall); 341 } 342 // expect "pragma syscalls end" 343 tokenizer.ExpectNextToken("pragma"); 344 tokenizer.ExpectNextToken("syscalls"); 345 tokenizer.ExpectNextToken("end"); 346 } 347 348 void _ParseSyscall(Tokenizer &tokenizer, Function &syscall) 349 { 350 // get return type and function name 351 vector<string> returnType; 352 while (tokenizer.GetNextToken() != "(") { 353 string token = tokenizer.GetCurrentToken(); 354 // strip leading "extern" 355 if (!returnType.empty() || token != "extern") 356 returnType.push_back(token); 357 } 358 if (returnType.size() < 2) { 359 throw ParseException("Error while parsing function " 360 "return type."); 361 } 362 syscall.SetName(returnType[returnType.size() - 1]); 363 returnType.pop_back(); 364 string returnTypeString(returnType[0]); 365 for (int i = 1; i < (int)returnType.size(); i++) { 366 returnTypeString += " "; 367 returnTypeString += returnType[i]; 368 } 369 syscall.SetReturnType(returnTypeString); 370 // get arguments 371 if (!tokenizer.CheckNextToken(")")) { 372 _ParseParameter(tokenizer, syscall); 373 while (!tokenizer.CheckNextToken(")")) { 374 tokenizer.ExpectNextToken(","); 375 _ParseParameter(tokenizer, syscall); 376 } 377 } 378 tokenizer.ExpectNextToken(";"); 379 } 380 381 void _ParseParameter(Tokenizer &tokenizer, Function &syscall) 382 { 383 vector<string> type; 384 while (tokenizer.GetNextToken() != ")" 385 && tokenizer.GetCurrentToken() != ",") { 386 string token = tokenizer.GetCurrentToken(); 387 type.push_back(token); 388 if (token == "(") { 389 // This must be a function pointer. We deal with that in a 390 // separate method. 391 _ParseFunctionPointerParameter(tokenizer, syscall, type); 392 return; 393 } 394 } 395 tokenizer.PutCurrentToken(); 396 if (type.size() < 2) { 397 if (type.size() == 1 && type[0] == "void") { 398 // that's OK 399 return; 400 } 401 throw ParseException("Error while parsing function " 402 "parameter."); 403 } 404 type.pop_back(); // last component is the parameter name 405 string typeString(type[0]); 406 for (int i = 1; i < (int)type.size(); i++) { 407 typeString += " "; 408 typeString += type[i]; 409 } 410 syscall.AddParameter(typeString); 411 } 412 413 void _ParseFunctionPointerParameter(Tokenizer &tokenizer, Function &syscall, 414 vector<string> &type) 415 { 416 // When this method is entered, the return type and the opening 417 // parenthesis must already be parse and stored in the supplied type 418 // vector. 419 if (type.size() < 2) { 420 throw ParseException("Error parsing function parameter. " 421 "No return type."); 422 } 423 // read all the "*"s there are 424 while (tokenizer.CheckNextToken("*")) 425 type.push_back("*"); 426 // now comes the parameter name, if specified -- skip it 427 if (!tokenizer.CheckNextToken(")")) { 428 tokenizer.GetNextToken(); 429 tokenizer.ExpectNextToken(")"); 430 } 431 type.push_back(")"); 432 // the function parameters 433 tokenizer.ExpectNextToken("("); 434 type.push_back("("); 435 while (!tokenizer.CheckNextToken(")")) 436 type.push_back(tokenizer.GetNextToken()); 437 type.push_back(")"); 438 // compose the type string and add it to the syscall parameters 439 string typeString(type[0]); 440 for (int i = 1; i < (int)type.size(); i++) { 441 typeString += " "; 442 typeString += type[i]; 443 } 444 syscall.AddParameter(typeString); 445 } 446 447 private: 448 ifstream fHeaderFile; 449 const char *fDispatcherTemplateFile; 450 const char *fCallsFile; 451 const char *fDispatcherFile; 452 }; 453 454 455 // main 456 int 457 main(int argc, char **argv) 458 { 459 try { 460 return Main().Run(argc, argv); 461 } catch (Exception &exception) { 462 fprintf(stderr, "%s\n", exception.what()); 463 return 1; 464 } 465 } 466 467