diff options
Diffstat (limited to 'circuitpython/ports/raspberrypi/sdk/tools/pioasm/lexer.ll')
-rw-r--r-- | circuitpython/ports/raspberrypi/sdk/tools/pioasm/lexer.ll | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/circuitpython/ports/raspberrypi/sdk/tools/pioasm/lexer.ll b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/lexer.ll new file mode 100644 index 0000000..939b06f --- /dev/null +++ b/circuitpython/ports/raspberrypi/sdk/tools/pioasm/lexer.ll @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +%{ /* -*- C++ -*- */ +# include <cerrno> +# include <climits> +# include <cstdlib> +# include <cstring> +# include <string> +# include "pio_assembler.h" +# include "parser.hpp" + +#ifdef _MSC_VER +#pragma warning(disable : 4996) // fopen +#endif + +%} + +%option noyywrap nounput noinput batch debug never-interactive case-insensitive noline + +%{ + yy::parser::symbol_type make_INT(const std::string &s, const yy::parser::location_type& loc); + yy::parser::symbol_type make_HEX(const std::string &s, const yy::parser::location_type& loc); + yy::parser::symbol_type make_BINARY(const std::string &s, const yy::parser::location_type& loc); +%} + +blank [ \t] +whitesp {blank}+ + +comment (";"|"//")[^\n]* + +digit [0-9] +id [a-zA-Z_][a-zA-Z0-9_]* + +binary "0b"[01]+ +int {digit}+ +hex "0x"[0-9a-fA-F]+ +directive \.{id} + +output_fmt [^%\n]+ + +%{ + // Code run each time a pattern is matched. + # define YY_USER_ACTION loc.columns (yyleng); +%} + +%x code_block +%x c_comment +%x lang_opt + +%% + std::string code_block_contents; + yy::location code_block_start; +%{ + // A handy shortcut to the location held by the pio_assembler. + yy::location& loc = pioasm.location; + // Code run each time yylex is called. + loc.step(); +%} + +{blank}+ loc.step(); +\n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); return yy::parser::make_NEWLINE(loc_newline); } + +"%"{blank}*{output_fmt}{blank}*"{" { + BEGIN(code_block); + code_block_contents = ""; + code_block_start = loc; + std::string tmp(yytext); + tmp = tmp.substr(1, tmp.length() - 2); + tmp = tmp.erase(0, tmp.find_first_not_of(" \t")); + tmp = tmp.erase(tmp.find_last_not_of(" \t") + 1); + return yy::parser::make_CODE_BLOCK_START( tmp, loc); + } +<code_block>{ + {blank}+ loc.step(); + \n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); } + "%}" { BEGIN(INITIAL); auto loc2 = loc; loc2.begin = code_block_start.begin; return yy::parser::make_CODE_BLOCK_CONTENTS(code_block_contents, loc2); } + .* { code_block_contents += std::string(yytext) + "\n"; } +} + +<c_comment>{ + {blank}+ loc.step(); + "*/" { BEGIN(INITIAL); } + "*" { } + [^\n\*]* { } + \n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); } +} + +<lang_opt>{ +\"[^\n]*\" return yy::parser::make_STRING(yytext, loc); +{blank}+ loc.step(); +"=" return yy::parser::make_EQUAL(loc); +{int} return make_INT(yytext, loc); +{hex} return make_HEX(yytext, loc); +{binary} return make_BINARY(yytext, loc); +[^ \t\n\"=]+ return yy::parser::make_NON_WS(yytext, loc); +\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); } +. { throw yy::parser::syntax_error(loc, "invalid character: " + std::string(yytext)); } +} + +"/*" { BEGIN(c_comment); } +"," return yy::parser::make_COMMA(loc); +"::" return yy::parser::make_REVERSE(loc); +":" return yy::parser::make_COLON(loc); +"[" return yy::parser::make_LBRACKET(loc); +"]" return yy::parser::make_RBRACKET(loc); +"(" return yy::parser::make_LPAREN(loc); +")" return yy::parser::make_RPAREN(loc); +"+" return yy::parser::make_PLUS(loc); +"--" return yy::parser::make_POST_DECREMENT(loc); +"−−" return yy::parser::make_POST_DECREMENT(loc); +"-" return yy::parser::make_MINUS(loc); +"*" return yy::parser::make_MULTIPLY(loc); +"/" return yy::parser::make_DIVIDE(loc); +"|" return yy::parser::make_OR(loc); +"&" return yy::parser::make_AND(loc); +"^" return yy::parser::make_XOR(loc); +"!=" return yy::parser::make_NOT_EQUAL(loc); +"!" return yy::parser::make_NOT(loc); +"~" return yy::parser::make_NOT(loc); + +".program" return yy::parser::make_PROGRAM(loc); +".wrap_target" return yy::parser::make_WRAP_TARGET(loc); +".wrap" return yy::parser::make_WRAP(loc); +".word" return yy::parser::make_WORD(loc); +".define" return yy::parser::make_DEFINE(loc); +".side_set" return yy::parser::make_SIDE_SET(loc); +".origin" return yy::parser::make_ORIGIN(loc); +".lang_opt" { BEGIN(lang_opt); return yy::parser::make_LANG_OPT(loc); } +{directive} return yy::parser::make_UNKNOWN_DIRECTIVE(yytext, loc); + +"JMP" return yy::parser::make_JMP(loc); +"WAIT" return yy::parser::make_WAIT(loc); +"IN" return yy::parser::make_IN(loc); +"OUT" return yy::parser::make_OUT(loc); +"PUSH" return yy::parser::make_PUSH(loc); +"PULL" return yy::parser::make_PULL(loc); +"MOV" return yy::parser::make_MOV(loc); +"IRQ" return yy::parser::make_IRQ(loc); +"SET" return yy::parser::make_SET(loc); +"NOP" return yy::parser::make_NOP(loc); + +"PUBLIC" return yy::parser::make_PUBLIC(loc); + +"OPTIONAL" return yy::parser::make_OPTIONAL(loc); +"OPT" return yy::parser::make_OPTIONAL(loc); +"SIDE" return yy::parser::make_SIDE(loc); +"SIDESET" return yy::parser::make_SIDE(loc); +"SIDE_SET" return yy::parser::make_SIDE(loc); +"PIN" return yy::parser::make_PIN(loc); +"GPIO" return yy::parser::make_GPIO(loc); +"OSRE" return yy::parser::make_OSRE(loc); + +"PINS" return yy::parser::make_PINS(loc); +"NULL" return yy::parser::make_NULL(loc); +"PINDIRS" return yy::parser::make_PINDIRS(loc); +"X" return yy::parser::make_X(loc); +"Y" return yy::parser::make_Y(loc); +"PC" return yy::parser::make_PC(loc); +"EXEC" return yy::parser::make_EXEC(loc); +"ISR" return yy::parser::make_ISR(loc); +"OSR" return yy::parser::make_OSR(loc); +"STATUS" return yy::parser::make_STATUS(loc); + +"BLOCK" return yy::parser::make_BLOCK(loc); +"NOBLOCK" return yy::parser::make_NOBLOCK(loc); +"IFFULL" return yy::parser::make_IFFULL(loc); +"IFEMPTY" return yy::parser::make_IFEMPTY(loc); +"REL" return yy::parser::make_REL(loc); + +"CLEAR" return yy::parser::make_CLEAR(loc); +"NOWAIT" return yy::parser::make_NOWAIT(loc); + +"ONE" return yy::parser::make_INT(1, loc); +"ZERO" return yy::parser::make_INT(0, loc); + +<<EOF>> return yy::parser::make_END(loc); + +{int} return make_INT(yytext, loc); +{hex} return make_HEX(yytext, loc); +{binary} return make_BINARY(yytext, loc); + +{id} return yy::parser::make_ID(yytext, loc); + +{comment} { } + +. { throw yy::parser::syntax_error(loc, "invalid character: " + std::string(yytext)); } + +%% + +yy::parser::symbol_type make_INT(const std::string &s, const yy::parser::location_type& loc) +{ + errno = 0; + long n = strtol (s.c_str(), NULL, 10); + if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) + throw yy::parser::syntax_error (loc, "integer is out of range: " + s); + return yy::parser::make_INT((int) n, loc); +} + +yy::parser::symbol_type make_HEX(const std::string &s, const yy::parser::location_type& loc) +{ + errno = 0; + long n = strtol (s.c_str() + 2, NULL, 16); + if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) + throw yy::parser::syntax_error (loc, "hex is out of range: " + s); + return yy::parser::make_INT((int) n, loc); +} + +yy::parser::symbol_type make_BINARY(const std::string &s, const yy::parser::location_type& loc) +{ + errno = 0; + long n = strtol (s.c_str()+2, NULL, 2); + if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) + throw yy::parser::syntax_error (loc, "binary is out of range: " + s); + return yy::parser::make_INT((int) n, loc); +} + +void pio_assembler::scan_begin () +{ + yy_flex_debug = false; + if (source.empty () || source == "-") + yyin = stdin; + else if (!(yyin = fopen (source.c_str (), "r"))) + { + std::cerr << "cannot open " << source << ": " << strerror(errno) << '\n'; + exit (EXIT_FAILURE); + } +} + +void pio_assembler::scan_end () +{ + fclose (yyin); +} |