vmfparser.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #include "vmfparser.h"
  2. #include "libc.h"
  3. typedef enum {
  4. VMFTokenType_End,
  5. VMFTokenType_Error,
  6. VMFTokenType_String,
  7. VMFTokenType_Open,
  8. VMFTokenType_Close
  9. } VMFTokenType;
  10. typedef struct {
  11. VMFTokenType type;
  12. StringView string;
  13. } VMFToken;
  14. static VMFToken readNextToken(VMFState *state) {
  15. const char *c = state->data.str;
  16. const char * const end = state->data.str + state->data.length;
  17. const char *error_message = NULL;
  18. #define CHECK_END (end == c || *c == '\0')
  19. #define REPORT_ERROR(msg) \
  20. do {\
  21. error_message = msg; \
  22. token.type = VMFTokenType_Error; \
  23. goto exit; \
  24. } while(0)
  25. VMFToken token;
  26. token.string.str = NULL;
  27. token.string.length = 0;
  28. token.type = VMFTokenType_End;
  29. for (;;) {
  30. for (;; ++c) {
  31. if (CHECK_END) {
  32. --c;
  33. goto exit;
  34. }
  35. if (!isspace(*c))
  36. break;
  37. }
  38. switch(*c) {
  39. case '{':
  40. token.string.str = c;
  41. token.string.length = 1;
  42. token.type = VMFTokenType_Open;
  43. break;
  44. case '}':
  45. token.string.str = c;
  46. token.string.length = 1;
  47. token.type = VMFTokenType_Close;
  48. break;
  49. case '/':
  50. ++c;
  51. if (CHECK_END || *c != '/')
  52. REPORT_ERROR("'/' expected");
  53. while(!CHECK_END && *c != '\n') ++c;
  54. continue;
  55. case '\"':
  56. token.string.str = ++c;
  57. for (;; ++c) {
  58. if (CHECK_END)
  59. REPORT_ERROR("\" is not closed at the end");
  60. if (*c == '\"')
  61. break;
  62. }
  63. token.string.length = c - token.string.str;
  64. token.type = VMFTokenType_String;
  65. break;
  66. default:
  67. token.string.str = c;
  68. while (!CHECK_END && isgraph(*c)) ++c;
  69. token.string.length = c - token.string.str;
  70. token.type = VMFTokenType_String;
  71. } /* switch(*c) */
  72. break;
  73. } /* forever */
  74. exit:
  75. if (error_message)
  76. PRINTF("Parsing error \"%s\" @%d (%.*s)", error_message,
  77. (int)(c - state->data.str), (int)(end - c < 32 ? end - c : 32), c);
  78. //else PRINTF("Token %d, (%.*s)", token.type, PRI_SVV(token.string));
  79. state->data.str = c + 1;
  80. state->data.length = end - c - 1;
  81. return token;
  82. }
  83. VMFResult vmfParse(VMFState *state) {
  84. VMFKeyValue kv;
  85. VMFAction action = VMFAction_Continue;
  86. for (;;) {
  87. switch (action) {
  88. case VMFAction_Continue:
  89. break;
  90. case VMFAction_Exit:
  91. return VMFResult_Success;
  92. case VMFAction_SemanticError:
  93. return VMFResult_SemanticError;
  94. }
  95. kv.key.str = kv.value.str = "";
  96. kv.key.length = kv.value.length = 0;
  97. VMFToken token = readNextToken(state);
  98. switch (token.type) {
  99. case VMFTokenType_String:
  100. kv.key = token.string;
  101. break;
  102. case VMFTokenType_Open:
  103. action = state->callback(state, VMFEntryType_SectionOpen, &kv);
  104. continue;
  105. case VMFTokenType_Close:
  106. action = state->callback(state, VMFEntryType_SectionClose, &kv);
  107. continue;
  108. case VMFTokenType_End:
  109. return VMFResult_Success;
  110. default:
  111. PRINTF("Unexpected token %d", token.type);
  112. return VMFResult_SyntaxError;
  113. }
  114. token = readNextToken(state);
  115. switch (token.type) {
  116. case VMFTokenType_String:
  117. kv.value = token.string;
  118. action = state->callback(state, VMFEntryType_KeyValue, &kv);
  119. continue;
  120. case VMFTokenType_Open:
  121. action = state->callback(state, VMFEntryType_SectionOpen, &kv);
  122. continue;
  123. default:
  124. PRINTF("Unexpected token %d", token.type);
  125. return VMFResult_SyntaxError;
  126. }
  127. } // forever
  128. } // vmfParse