1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <iostream> 18#include <sstream> 19 20#include "Scanner.h" 21#include "Specification.h" 22#include "Utilities.h" 23 24using namespace std; 25 26// Maximum of errors we'll report before bailing out. 27const int MAX_ERRORS = 10; 28 29Scanner::Scanner(const string& fileName, FILE* file) 30 : mFileName(fileName), mFile(file), mLineNumber(0), mTagConsumed(true), mErrorCount(0) { 31} 32 33bool Scanner::atEnd() { 34 return (mTagConsumed && feof(mFile)) || mErrorCount > MAX_ERRORS; 35} 36 37int Scanner::getChar() { 38 int c = fgetc(mFile); 39 if (c == '\n') { 40 mLineNumber++; 41 } 42 return c; 43} 44 45void Scanner::readUpTo(char delimiter, string* segment) { 46 for (;;) { 47 int c = getChar(); 48 if (c == EOF || c == '\n') { 49 break; 50 } 51 segment->push_back((char)c); 52 if (c == delimiter) { 53 break; 54 } 55 } 56} 57 58void Scanner::readRestOfLine(string* segment) { 59 for (;;) { 60 int c = getChar(); 61 if (c == EOF || c == '\n') { 62 return; 63 } 64 segment->push_back((char)c); 65 } 66} 67 68bool Scanner::getNextEntry() { 69 mTag.clear(); 70 mValue.clear(); 71 for (;;) { 72 int c = getChar(); 73 if (c == EOF) { 74 return false; 75 } 76 if (c == '#') { 77 // Skip the comment 78 string comment; 79 readRestOfLine(&comment); 80 continue; 81 } 82 if (c == ' ') { 83 readRestOfLine(&mValue); 84 break; 85 } else if (c == '\n') { 86 break; 87 } else { 88 mTag = c; 89 readUpTo(':', &mTag); 90 readRestOfLine(&mValue); 91 trimSpaces(&mValue); 92 break; 93 } 94 } 95 return true; 96} 97 98ostream& Scanner::error() { 99 return error(mLineNumber); 100} 101 102ostream& Scanner::error(int lineNumber) { 103 if (++mErrorCount <= MAX_ERRORS) { 104 cerr << mFileName << ":" << lineNumber << ": error: "; 105 } 106 return cerr; 107} 108 109void Scanner::skipBlankEntries() { 110 while (findOptionalTag("")) { 111 if (!mValue.empty()) { 112 error() << "Unexpected: \" " << mValue << "\".\n"; 113 } 114 } 115} 116 117bool Scanner::findTag(const char* tag) { 118 bool found = findOptionalTag(tag); 119 if (!found) { 120 error() << "Found \"" << mTag << "\" while looking for \"" << tag << "\".\n"; 121 } 122 mTagConsumed = true; 123 return found; 124} 125 126bool Scanner::findOptionalTag(const char* tag) { 127 if (mTagConsumed) { 128 if (!getNextEntry()) { 129 return false; 130 } 131 } 132 mTagConsumed = (mTag == tag); 133 return mTagConsumed; 134} 135 136void Scanner::skipUntilTag(const char* tag) { 137 while(!findOptionalTag(tag)) { 138 mTagConsumed = true; 139 } 140} 141 142void Scanner::checkNoValue() { 143 if (!mValue.empty()) { 144 error() << "Did not expect \"" << mValue << "\" after \"" << mTag << "\".\n"; 145 } 146} 147 148void Scanner::parseDocumentation(string* s, string* documentation) { 149 size_t docStart = s->find(", \""); 150 if (docStart == string::npos) { 151 documentation->erase(); 152 } else { 153 size_t first = docStart + 3; 154 size_t last = s->find('\"', first); 155 if (last == string::npos) { 156 error() << "Missing closing double quote\n"; 157 } 158 *documentation = s->substr(first, last - first); 159 s->erase(docStart); 160 } 161} 162 163ParameterEntry* Scanner::parseArgString(bool isReturn) { 164 string s = mValue; 165 ParameterEntry* p = new ParameterEntry(); 166 parseDocumentation(&s, &p->documentation); 167 168 size_t optionStart = s.find(", "); 169 if (optionStart != string::npos) { 170 p->testOption = s.substr(optionStart + 2); 171 s.erase(optionStart); 172 } 173 174 trimSpaces(&s); 175 if (!isReturn) { 176 size_t nameStart = s.rfind(' '); 177 if (nameStart == string::npos) { 178 if (s == "...") { 179 p->name = s; 180 p->type = s; 181 p->lineNumber = mLineNumber; 182 return p; 183 } else { 184 error() << "Missing variable name\n"; 185 } 186 } else { 187 p->name = s.substr(nameStart + 1); 188 s.erase(nameStart); 189 if (p->name.find('*') != string::npos) { 190 error() << "The '*' should be attached to the type\n"; 191 } 192 } 193 } 194 195 if (s == "void" && !isReturn) { 196 error() << "void is only allowed for ret:\n"; 197 } 198 p->type = s; 199 p->lineNumber = mLineNumber; 200 return p; 201} 202