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