Build tool
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

BXParser.cc 7.0KB

3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. #include "BXParser.h"
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. int BXParser::get() {
  7. int c = buf_.get();
  8. ch_ += 1;
  9. if (c == '\n') {
  10. ch_ = 1;
  11. line_ += 1;
  12. }
  13. return c;
  14. }
  15. int BXParser::peek() {
  16. return buf_.peek();
  17. }
  18. int BXParser::peek2() {
  19. return buf_.peek2();
  20. }
  21. BXParser::Operator BXParser::readOperator() {
  22. int ch2 = peek2();
  23. if (peek() == ':' && ch2 == '=') {
  24. skip(); // ':'
  25. skip(); // '='
  26. return Operator::COLON_EQUALS;
  27. } else if (peek() == '+' && ch2 == '=') {
  28. skip(); // '+'
  29. skip(); // '='
  30. return Operator::PLUS_EQUALS;
  31. } else if (peek() == '=' && ch2 == '+') {
  32. skip(); // '='
  33. skip(); // '+'
  34. return Operator::EQUALS_PLUS;
  35. }
  36. return Operator::NONE;
  37. }
  38. void BXParser::skip(char expected) {
  39. int ch = get();
  40. if (ch == EOF) {
  41. error(std::string("Expected '") + expected + "', got EOF");
  42. } else if (ch != expected) {
  43. error(std::string("Expected '") + expected + "', got '" + (char)ch + "'");
  44. }
  45. }
  46. [[noreturn]] void BXParser::error(std::string msg) {
  47. throw BXParseError(std::to_string(line_) + ":" + std::to_string(ch_) + ": " + msg);
  48. }
  49. static bool isWhitespace(int ch) {
  50. if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
  51. return true;
  52. return false;
  53. }
  54. void BXParser::skipWhitespace() {
  55. if (flags_ & FLAG_ONE_LINE) {
  56. int ch;
  57. while (isWhitespace(ch = peek()) && ch != '\r' && ch != '\n')
  58. get();
  59. } else {
  60. while (isWhitespace(peek()))
  61. get();
  62. }
  63. }
  64. char BXParser::parseEscape() {
  65. skip(); // '\'
  66. int ch;
  67. switch (ch = get()) {
  68. case EOF:
  69. error("Unexpected EOF");
  70. case 'n':
  71. return '\n';
  72. case 'r':
  73. return '\r';
  74. case 't':
  75. return '\t';
  76. default:
  77. return (char)ch;
  78. }
  79. }
  80. static void appendVariableToString(
  81. const BXVariables &vars, std::string &name,
  82. std::string &value) {
  83. if (name.size() == 0)
  84. return;
  85. auto it = vars.find(name);
  86. if (it == vars.end())
  87. return;
  88. auto &vec = it->second;
  89. bool first = true;
  90. for (auto &part: vec) {
  91. if (!first) {
  92. value += ' ';
  93. }
  94. first = false;
  95. value += part;
  96. }
  97. }
  98. static void appendVariableToArray(
  99. const BXVariables &vars, const std::string &name,
  100. std::vector<std::string> &values) {
  101. if (name.size() == 0)
  102. return;
  103. auto it = vars.find(name);
  104. if (it == vars.end())
  105. return;
  106. auto &vec = it->second;
  107. for (auto &part: vec) {
  108. values.push_back(part);
  109. }
  110. }
  111. void BXParser::parseExpansion(const BXVariables &vars, std::vector<std::string> &values) {
  112. skip(); // '$'
  113. std::string str;
  114. switch (peek()) {
  115. case '{':
  116. skip();
  117. parseString(vars, str, '}');
  118. skip('}');
  119. appendVariableToArray(vars, str, values);
  120. break;
  121. default:
  122. if (!parseIdentifier(str)) {
  123. error("No identifier after $.");
  124. }
  125. appendVariableToArray(vars, str, values);
  126. break;
  127. }
  128. }
  129. void BXParser::parseQuotedExpansion(const BXVariables &vars, std::string &content) {
  130. skip(); // '$'
  131. std::string str;
  132. switch (peek()) {
  133. case '{':
  134. skip();
  135. parseString(vars, str, '}');
  136. skip('}');
  137. appendVariableToString(vars, str, content);
  138. break;
  139. default:
  140. if (!parseIdentifier(str)) {
  141. error("No identifier after $.");
  142. }
  143. appendVariableToString(vars, str, content);
  144. break;
  145. }
  146. }
  147. void BXParser::parseQuotedString(const BXVariables &vars, std::string &content) {
  148. skip(); // '"'
  149. int ch;
  150. while ((ch = peek()) != EOF) {
  151. switch (ch) {
  152. case EOF:
  153. error("Unexpected EOF");
  154. case '\\':
  155. content.push_back(parseEscape());
  156. break;
  157. case '$':
  158. parseQuotedExpansion(vars, content);
  159. break;
  160. case '"':
  161. skip();
  162. return;
  163. default:
  164. content.push_back(get());
  165. break;
  166. }
  167. }
  168. }
  169. bool BXParser::parseString(const BXVariables &vars, std::string &content, int sep) {
  170. bool success = false;
  171. int ch;
  172. while (1) {
  173. ch = peek();
  174. if ((sep > 0 && ch == sep) || isWhitespace(ch)) {
  175. return success;
  176. }
  177. switch (ch) {
  178. case EOF:
  179. return success;
  180. case '\\':
  181. content.push_back(parseEscape());
  182. success = true;
  183. break;
  184. case '$':
  185. parseQuotedExpansion(vars, content);
  186. success = true;
  187. break;
  188. case '"':
  189. parseQuotedString(vars, content);
  190. success = true;
  191. break;
  192. default:
  193. if (ch == ':' && peek2() == '=')
  194. return success;
  195. content.push_back(get());
  196. success = true;
  197. break;
  198. }
  199. }
  200. }
  201. bool BXParser::parseIdentifier(std::string &content) {
  202. int ch = peek();
  203. if (!(
  204. (ch >= 'a' && ch <= 'z') ||
  205. (ch >= 'A' && ch <= 'Z') ||
  206. (ch == '_'))) {
  207. return false;
  208. }
  209. content += get();
  210. while (1) {
  211. ch = peek();
  212. if (!(
  213. (ch >= '0' && ch <= '9') ||
  214. (ch >= 'a' && ch <= 'z') ||
  215. (ch >= 'A' && ch <= 'Z') ||
  216. (ch == '_'))) {
  217. return true;
  218. }
  219. content += get();
  220. }
  221. }
  222. void BXParser::parse(BXVariables &vars) {
  223. std::string key, value;
  224. std::vector<std::string> values;
  225. skipWhitespace();
  226. if (!parseString(vars, key)) {
  227. return;
  228. }
  229. skipWhitespace();
  230. Operator prevOper = readOperator();
  231. if (prevOper == Operator::NONE) {
  232. error("Expected operator.");
  233. }
  234. auto doAssignment = [&] {
  235. switch (prevOper) {
  236. case Operator::COLON_EQUALS:
  237. vars[key] = std::move(values);
  238. values.clear();
  239. break;
  240. case Operator::PLUS_EQUALS:
  241. {
  242. auto &vec = vars[key];
  243. vec.reserve(vec.size() + values.size());
  244. for (size_t i = 0; i < values.size(); ++i) {
  245. vec.push_back(std::move(values[i]));
  246. }
  247. }
  248. values.clear();
  249. break;
  250. case Operator::EQUALS_PLUS:
  251. {
  252. auto &vec = vars[key];
  253. vec.reserve(vec.size() + values.size());
  254. for (size_t i = 0; i < vec.size(); ++i) {
  255. values.push_back(std::move(vec[i]));
  256. }
  257. vec = std::move(values);
  258. }
  259. values.clear();
  260. break;
  261. case Operator::NONE:
  262. break;
  263. }
  264. };
  265. while (true) {
  266. skipWhitespace();
  267. // Parse next value
  268. if (peek() == '$') {
  269. parseExpansion(vars, values);
  270. value.clear();
  271. continue; // We can't have an assignment after an expansion
  272. } else if (!parseString(vars, value)) {
  273. break;
  274. }
  275. skipWhitespace();
  276. // If there's an operator next, the value we just read was a actually a key.
  277. // Otherwise, it was just another value.
  278. Operator op = readOperator();
  279. if (op == Operator::NONE) {
  280. values.push_back(std::move(value));
  281. value.clear();
  282. } else {
  283. if (value.size() == 0) {
  284. error("Expected string before assignment operator");
  285. }
  286. doAssignment();
  287. prevOper = op;
  288. key = std::move(value);
  289. value.clear();
  290. }
  291. }
  292. doAssignment();
  293. }
  294. void BXParser::parseList(const BXVariables &vars, std::vector<std::string> &values) {
  295. while (true) {
  296. skipWhitespace();
  297. std::string value;
  298. if (!parseString(vars, value)) {
  299. break;
  300. }
  301. values.push_back(std::move(value));
  302. }
  303. }
  304. void BXWriter::escape(const std::string &str) {
  305. buf_.put('"');
  306. for (char ch: str) {
  307. if (ch == '$' || ch == '"' || ch == '\\') {
  308. buf_.put('\\');
  309. }
  310. buf_.put(ch);
  311. }
  312. buf_.put('"');
  313. }
  314. void BXWriter::write(const BXVariables &vars) {
  315. for (const auto &pair: vars) {
  316. size_t chars = 0;
  317. buf_.put(pair.first);
  318. buf_.put(" :=");
  319. for (auto &val: pair.second) {
  320. if (chars >= 80) {
  321. buf_.put('\n');
  322. buf_.put('\t');
  323. chars = 0;
  324. } else {
  325. buf_.put(' ');
  326. }
  327. escape(val);
  328. chars += val.size();
  329. }
  330. buf_.put('\n');
  331. }
  332. }