lexer.ll 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. %{ /* -*- C++ -*- */
  7. # include <cerrno>
  8. # include <climits>
  9. # include <cstdlib>
  10. # include <cstring>
  11. # include <string>
  12. # include "pio_assembler.h"
  13. # include "parser.hpp"
  14. #ifdef _MSC_VER
  15. #pragma warning(disable : 4996) // fopen
  16. #endif
  17. %}
  18. %option noyywrap nounput noinput batch debug never-interactive case-insensitive noline
  19. %{
  20. yy::parser::symbol_type make_INT(const std::string &s, const yy::parser::location_type& loc);
  21. yy::parser::symbol_type make_HEX(const std::string &s, const yy::parser::location_type& loc);
  22. yy::parser::symbol_type make_BINARY(const std::string &s, const yy::parser::location_type& loc);
  23. %}
  24. blank [ \t\r]
  25. whitesp {blank}+
  26. comment (";"|"//")[^\n]*
  27. digit [0-9]
  28. id [a-zA-Z_][a-zA-Z0-9_]*
  29. binary "0b"[01]+
  30. int {digit}+
  31. hex "0x"[0-9a-fA-F]+
  32. directive \.{id}
  33. output_fmt [^%\n]+
  34. %{
  35. // Code run each time a pattern is matched.
  36. # define YY_USER_ACTION loc.columns (yyleng);
  37. %}
  38. %x code_block
  39. %x c_comment
  40. %x lang_opt
  41. %%
  42. std::string code_block_contents;
  43. yy::location code_block_start;
  44. %{
  45. // A handy shortcut to the location held by the pio_assembler.
  46. yy::location& loc = pioasm.location;
  47. // Code run each time yylex is called.
  48. loc.step();
  49. %}
  50. {blank}+ loc.step();
  51. \n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); return yy::parser::make_NEWLINE(loc_newline); }
  52. "%"{blank}*{output_fmt}{blank}*"{" {
  53. BEGIN(code_block);
  54. code_block_contents = "";
  55. code_block_start = loc;
  56. std::string tmp(yytext);
  57. tmp = tmp.substr(1, tmp.length() - 2);
  58. tmp = tmp.erase(0, tmp.find_first_not_of(" \t"));
  59. tmp = tmp.erase(tmp.find_last_not_of(" \t") + 1);
  60. return yy::parser::make_CODE_BLOCK_START( tmp, loc);
  61. }
  62. <code_block>{
  63. {blank}+ loc.step();
  64. \n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); }
  65. "%}"{blank}* { BEGIN(INITIAL); auto loc2 = loc; loc2.begin = code_block_start.begin; return yy::parser::make_CODE_BLOCK_CONTENTS(code_block_contents, loc2); }
  66. .* { code_block_contents += std::string(yytext) + "\n"; }
  67. }
  68. <c_comment>{
  69. {blank}+ loc.step();
  70. "*/" { BEGIN(INITIAL); }
  71. "*" { }
  72. [^\n\*]* { }
  73. \n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); }
  74. }
  75. <lang_opt>{
  76. \"[^\n]*\" return yy::parser::make_STRING(yytext, loc);
  77. {blank}+ loc.step();
  78. "=" return yy::parser::make_EQUAL(loc);
  79. {int} return make_INT(yytext, loc);
  80. {hex} return make_HEX(yytext, loc);
  81. {binary} return make_BINARY(yytext, loc);
  82. [^ \t\n\"=]+ return yy::parser::make_NON_WS(yytext, loc);
  83. \n+ { BEGIN(INITIAL); auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); return yy::parser::make_NEWLINE(loc_newline); }
  84. . { throw yy::parser::syntax_error(loc, "invalid character: " + std::string(yytext)); }
  85. }
  86. "/*" { BEGIN(c_comment); }
  87. "," return yy::parser::make_COMMA(loc);
  88. "::" return yy::parser::make_REVERSE(loc);
  89. ":" return yy::parser::make_COLON(loc);
  90. "[" return yy::parser::make_LBRACKET(loc);
  91. "]" return yy::parser::make_RBRACKET(loc);
  92. "(" return yy::parser::make_LPAREN(loc);
  93. ")" return yy::parser::make_RPAREN(loc);
  94. "+" return yy::parser::make_PLUS(loc);
  95. "--" return yy::parser::make_POST_DECREMENT(loc);
  96. "−−" return yy::parser::make_POST_DECREMENT(loc);
  97. "-" return yy::parser::make_MINUS(loc);
  98. "*" return yy::parser::make_MULTIPLY(loc);
  99. "/" return yy::parser::make_DIVIDE(loc);
  100. "|" return yy::parser::make_OR(loc);
  101. "&" return yy::parser::make_AND(loc);
  102. "^" return yy::parser::make_XOR(loc);
  103. "!=" return yy::parser::make_NOT_EQUAL(loc);
  104. "!" return yy::parser::make_NOT(loc);
  105. "~" return yy::parser::make_NOT(loc);
  106. ".program" return yy::parser::make_PROGRAM(loc);
  107. ".wrap_target" return yy::parser::make_WRAP_TARGET(loc);
  108. ".wrap" return yy::parser::make_WRAP(loc);
  109. ".word" return yy::parser::make_WORD(loc);
  110. ".define" return yy::parser::make_DEFINE(loc);
  111. ".side_set" return yy::parser::make_SIDE_SET(loc);
  112. ".origin" return yy::parser::make_ORIGIN(loc);
  113. ".lang_opt" { BEGIN(lang_opt); return yy::parser::make_LANG_OPT(loc); }
  114. {directive} return yy::parser::make_UNKNOWN_DIRECTIVE(yytext, loc);
  115. "JMP" return yy::parser::make_JMP(loc);
  116. "WAIT" return yy::parser::make_WAIT(loc);
  117. "IN" return yy::parser::make_IN(loc);
  118. "OUT" return yy::parser::make_OUT(loc);
  119. "PUSH" return yy::parser::make_PUSH(loc);
  120. "PULL" return yy::parser::make_PULL(loc);
  121. "MOV" return yy::parser::make_MOV(loc);
  122. "IRQ" return yy::parser::make_IRQ(loc);
  123. "SET" return yy::parser::make_SET(loc);
  124. "NOP" return yy::parser::make_NOP(loc);
  125. "PUBLIC" return yy::parser::make_PUBLIC(loc);
  126. "OPTIONAL" return yy::parser::make_OPTIONAL(loc);
  127. "OPT" return yy::parser::make_OPTIONAL(loc);
  128. "SIDE" return yy::parser::make_SIDE(loc);
  129. "SIDESET" return yy::parser::make_SIDE(loc);
  130. "SIDE_SET" return yy::parser::make_SIDE(loc);
  131. "PIN" return yy::parser::make_PIN(loc);
  132. "GPIO" return yy::parser::make_GPIO(loc);
  133. "OSRE" return yy::parser::make_OSRE(loc);
  134. "PINS" return yy::parser::make_PINS(loc);
  135. "NULL" return yy::parser::make_NULL(loc);
  136. "PINDIRS" return yy::parser::make_PINDIRS(loc);
  137. "X" return yy::parser::make_X(loc);
  138. "Y" return yy::parser::make_Y(loc);
  139. "PC" return yy::parser::make_PC(loc);
  140. "EXEC" return yy::parser::make_EXEC(loc);
  141. "ISR" return yy::parser::make_ISR(loc);
  142. "OSR" return yy::parser::make_OSR(loc);
  143. "STATUS" return yy::parser::make_STATUS(loc);
  144. "BLOCK" return yy::parser::make_BLOCK(loc);
  145. "NOBLOCK" return yy::parser::make_NOBLOCK(loc);
  146. "IFFULL" return yy::parser::make_IFFULL(loc);
  147. "IFEMPTY" return yy::parser::make_IFEMPTY(loc);
  148. "REL" return yy::parser::make_REL(loc);
  149. "CLEAR" return yy::parser::make_CLEAR(loc);
  150. "NOWAIT" return yy::parser::make_NOWAIT(loc);
  151. "ONE" return yy::parser::make_INT(1, loc);
  152. "ZERO" return yy::parser::make_INT(0, loc);
  153. <<EOF>> return yy::parser::make_END(loc);
  154. {int} return make_INT(yytext, loc);
  155. {hex} return make_HEX(yytext, loc);
  156. {binary} return make_BINARY(yytext, loc);
  157. {id} return yy::parser::make_ID(yytext, loc);
  158. {comment} { }
  159. . { throw yy::parser::syntax_error(loc, "invalid character: " + std::string(yytext)); }
  160. %%
  161. yy::parser::symbol_type make_INT(const std::string &s, const yy::parser::location_type& loc)
  162. {
  163. errno = 0;
  164. long n = strtol (s.c_str(), NULL, 10);
  165. if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))
  166. throw yy::parser::syntax_error (loc, "integer is out of range: " + s);
  167. return yy::parser::make_INT((int) n, loc);
  168. }
  169. yy::parser::symbol_type make_HEX(const std::string &s, const yy::parser::location_type& loc)
  170. {
  171. errno = 0;
  172. long n = strtol (s.c_str() + 2, NULL, 16);
  173. if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))
  174. throw yy::parser::syntax_error (loc, "hex is out of range: " + s);
  175. return yy::parser::make_INT((int) n, loc);
  176. }
  177. yy::parser::symbol_type make_BINARY(const std::string &s, const yy::parser::location_type& loc)
  178. {
  179. errno = 0;
  180. long n = strtol (s.c_str()+2, NULL, 2);
  181. if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))
  182. throw yy::parser::syntax_error (loc, "binary is out of range: " + s);
  183. return yy::parser::make_INT((int) n, loc);
  184. }
  185. void pio_assembler::scan_begin ()
  186. {
  187. yy_flex_debug = false;
  188. if (source.empty () || source == "-")
  189. yyin = stdin;
  190. else if (!(yyin = fopen (source.c_str (), "r")))
  191. {
  192. std::cerr << "cannot open " << source << ": " << strerror(errno) << '\n';
  193. exit (EXIT_FAILURE);
  194. }
  195. }
  196. void pio_assembler::scan_end ()
  197. {
  198. fclose (yyin);
  199. }