parser.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #pragma once
  2. #include <string_view>
  3. #include <cstring>
  4. #include <queue>
  5. #include "obj.h"
  6. typedef uint8_t _TokenType;
  7. constexpr const char* __TOKENS[] = {
  8. "@error", "@eof", "@eol", "@sof",
  9. ".", ",", ":", ";", "#", "(", ")", "[", "]", "{", "}", "%",
  10. "+", "-", "*", "/", "//", "**", "=", ">", "<",
  11. "==", "!=", ">=", "<=",
  12. "+=", "-=", "*=", "/=", "//=",
  13. /** KW_BEGIN **/
  14. "class", "import", "as", "def", "lambda", "pass", "del",
  15. "None", "in", "is", "and", "or", "not", "True", "False",
  16. "while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise",
  17. /** KW_END **/
  18. "is not", "not in",
  19. "@id", "@num", "@str", "@fstr",
  20. "@indent", "@dedent"
  21. };
  22. const _TokenType __TOKENS_LEN = sizeof(__TOKENS) / sizeof(__TOKENS[0]);
  23. constexpr _TokenType TK(const char* const token) {
  24. for(int k=0; k<__TOKENS_LEN; k++){
  25. const char* i = __TOKENS[k];
  26. const char* j = token;
  27. while(*i && *j && *i == *j){
  28. i++; j++;
  29. }
  30. if(*i == *j) return k;
  31. }
  32. return 0;
  33. }
  34. #define TK_STR(t) __TOKENS[t]
  35. const _TokenType __KW_BEGIN = TK("class");
  36. const _TokenType __KW_END = TK("raise");
  37. const std::unordered_map<std::string_view, _TokenType> __KW_MAP = [](){
  38. std::unordered_map<std::string_view, _TokenType> map;
  39. for(int k=__KW_BEGIN; k<=__KW_END; k++) map[__TOKENS[k]] = k;
  40. return map;
  41. }();
  42. struct Token{
  43. _TokenType type;
  44. const char* start; //< Begining of the token in the source.
  45. int length; //< Number of chars of the token.
  46. int line; //< Line number of the token (1 based).
  47. PyVar value; //< Literal value of the token.
  48. const _Str str() const {
  49. return _Str(start, length);
  50. }
  51. const _Str info() const {
  52. _StrStream ss;
  53. _Str raw = str();
  54. if (raw == _Str("\n")) raw = "\\n";
  55. ss << line << ": " << TK_STR(type) << " '" << raw << "'";
  56. return ss.str();
  57. }
  58. };
  59. enum Precedence {
  60. PREC_NONE,
  61. PREC_ASSIGNMENT, // =
  62. PREC_COMMA, // ,
  63. PREC_LOGICAL_OR, // or
  64. PREC_LOGICAL_AND, // and
  65. PREC_EQUALITY, // == !=
  66. PREC_TEST, // in is
  67. PREC_COMPARISION, // < > <= >=
  68. PREC_TERM, // + -
  69. PREC_FACTOR, // * / %
  70. PREC_UNARY, // - not
  71. PREC_EXPONENT, // **
  72. PREC_CALL, // ()
  73. PREC_SUBSCRIPT, // []
  74. PREC_ATTRIB, // .index
  75. PREC_PRIMARY,
  76. };
  77. // The context of the parsing phase for the compiler.
  78. struct Parser {
  79. _Source src;
  80. const char* token_start;
  81. const char* current_char;
  82. int current_line = 1;
  83. Token previous, current;
  84. std::queue<Token> nexts;
  85. std::stack<int> indents;
  86. Token nextToken(){
  87. if(nexts.empty()) return makeErrToken();
  88. Token t = nexts.front();
  89. if(t.type == TK("@eof") && indents.size()>1){
  90. nexts.pop();
  91. indents.pop();
  92. return Token{TK("@dedent"), token_start, 0, current_line};
  93. }
  94. nexts.pop();
  95. return t;
  96. }
  97. char peekChar() {
  98. return *current_char;
  99. }
  100. char peekNextChar() {
  101. if (peekChar() == '\0') return '\0';
  102. return *(current_char + 1);
  103. }
  104. int eatSpaces(){
  105. int count = 0;
  106. while (true) {
  107. switch (peekChar()) {
  108. case ' ': count++; break;
  109. case '\t': count+=4; break;
  110. default: return count;
  111. }
  112. eatChar();
  113. }
  114. }
  115. bool eatIndentation(){
  116. int spaces = eatSpaces();
  117. // https://docs.python.org/3/reference/lexical_analysis.html#indentation
  118. if(spaces > indents.top()){
  119. indents.push(spaces);
  120. nexts.push(Token{TK("@indent"), token_start, 0, current_line});
  121. } else if(spaces < indents.top()){
  122. while(spaces < indents.top()){
  123. indents.pop();
  124. nexts.push(Token{TK("@dedent"), token_start, 0, current_line});
  125. }
  126. if(spaces != indents.top()){
  127. return false;
  128. }
  129. }
  130. return true;
  131. }
  132. char eatChar() {
  133. char c = peekChar();
  134. if(c == '\n') throw std::runtime_error("eatChar() cannot consume a newline");
  135. current_char++;
  136. return c;
  137. }
  138. char eatCharIncludeNewLine() {
  139. char c = peekChar();
  140. current_char++;
  141. if (c == '\n'){
  142. current_line++;
  143. src->lineStarts.push_back(current_char);
  144. }
  145. return c;
  146. }
  147. void eatName() {
  148. char c = peekChar();
  149. while (isalpha(c) || c=='_' || isdigit(c)) {
  150. eatChar();
  151. c = peekChar();
  152. }
  153. const char* name_start = token_start;
  154. int length = (int)(current_char - name_start);
  155. std::string_view name(name_start, length);
  156. if(__KW_MAP.count(name)){
  157. if(name == "not"){
  158. if(strncmp(current_char, " in", 3) == 0){
  159. current_char += 3;
  160. setNextToken(TK("not in"));
  161. return;
  162. }
  163. }else if(name == "is"){
  164. if(strncmp(current_char, " not", 4) == 0){
  165. current_char += 4;
  166. setNextToken(TK("is not"));
  167. return;
  168. }
  169. }
  170. setNextToken(__KW_MAP.at(name));
  171. } else {
  172. setNextToken(TK("@id"));
  173. }
  174. }
  175. void skipLineComment() {
  176. char c;
  177. while ((c = peekChar()) != '\0') {
  178. if (c == '\n') return;
  179. eatChar();
  180. }
  181. }
  182. // If the current char is [c] consume it and advance char by 1 and returns
  183. // true otherwise returns false.
  184. bool matchChar(char c) {
  185. if (peekChar() != c) return false;
  186. eatCharIncludeNewLine();
  187. return true;
  188. }
  189. // Returns an error token from the current position for reporting error.
  190. Token makeErrToken() {
  191. return Token{TK("@error"), token_start, (int)(current_char - token_start), current_line};
  192. }
  193. // Initialize the next token as the type.
  194. void setNextToken(_TokenType type, PyVar value=nullptr) {
  195. nexts.push( Token{
  196. type,
  197. token_start,
  198. (int)(current_char - token_start),
  199. current_line - ((type == TK("@eol")) ? 1 : 0),
  200. value
  201. });
  202. }
  203. void setNextTwoCharToken(char c, _TokenType one, _TokenType two) {
  204. if (matchChar(c)) setNextToken(two);
  205. else setNextToken(one);
  206. }
  207. Parser(_Source src) {
  208. this->src = src;
  209. this->token_start = src->source;
  210. this->current_char = src->source;
  211. this->nexts.push(Token{TK("@sof"), token_start, 0, current_line});
  212. this->indents.push(0);
  213. }
  214. };