1/* 2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7%{ /* -*- C++ -*- */ 8# include <cerrno> 9# include <climits> 10# include <cstdlib> 11# include <cstring> 12# include <string> 13# include "pio_assembler.h" 14# include "parser.hpp" 15 16#ifdef _MSC_VER 17#pragma warning(disable : 4996) // fopen 18#endif 19 20%} 21 22%option noyywrap nounput noinput batch debug never-interactive case-insensitive noline 23 24%{ 25 yy::parser::symbol_type make_INT(const std::string &s, const yy::parser::location_type& loc); 26 yy::parser::symbol_type make_FLOAT(const std::string &s, const yy::parser::location_type& loc); 27 yy::parser::symbol_type make_HEX(const std::string &s, const yy::parser::location_type& loc); 28 yy::parser::symbol_type make_BINARY(const std::string &s, const yy::parser::location_type& loc); 29%} 30 31blank [ \t\r] 32whitesp {blank}+ 33 34comment (";"|"//")[^\n]* 35 36digit [0-9] 37id [a-zA-Z_][a-zA-Z0-9_]* 38 39binary "0b"[01]+ 40int {digit}+ 41float {digit}*\.{digit}+ 42hex "0x"[0-9a-fA-F]+ 43directive \.{id} 44 45output_fmt [^%\n]+ 46 47%{ 48 // Code run each time a pattern is matched. 49 # define YY_USER_ACTION loc.columns (yyleng); 50%} 51 52%x code_block 53%x c_comment 54%x lang_opt 55 56%% 57 std::string code_block_contents; 58 yy::location code_block_start; 59%{ 60 // A handy shortcut to the location held by the pio_assembler. 61 yy::location& loc = pioasm.location; 62 // Code run each time yylex is called. 63 loc.step(); 64%} 65 66{blank}+ loc.step(); 67\n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); return yy::parser::make_NEWLINE(loc_newline); } 68 69"%"{blank}*{output_fmt}{blank}*"{" { 70 BEGIN(code_block); 71 code_block_contents = ""; 72 code_block_start = loc; 73 std::string tmp(yytext); 74 tmp = tmp.substr(1, tmp.length() - 2); 75 tmp = tmp.erase(0, tmp.find_first_not_of(" \t")); 76 tmp = tmp.erase(tmp.find_last_not_of(" \t") + 1); 77 return yy::parser::make_CODE_BLOCK_START( tmp, loc); 78 } 79<code_block>{ 80 {blank}+ loc.step(); 81 \n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); } 82 "%}"{blank}* { BEGIN(INITIAL); auto loc2 = loc; loc2.begin = code_block_start.begin; return yy::parser::make_CODE_BLOCK_CONTENTS(code_block_contents, loc2); } 83 .* { code_block_contents += std::string(yytext) + "\n"; } 84} 85 86<c_comment>{ 87 {blank}+ loc.step(); 88 "*/" { BEGIN(INITIAL); } 89 "*" { } 90 [^\n\*]* { } 91 \n+ { auto loc_newline = loc; loc_newline.end = loc_newline.begin; loc.lines(yyleng); loc.step(); } 92} 93 94<lang_opt>{ 95\"[^\n]*\" return yy::parser::make_STRING(yytext, loc); 96{blank}+ loc.step(); 97"=" return yy::parser::make_ASSIGN(loc); 98{int} return make_INT(yytext, loc); 99{hex} return make_HEX(yytext, loc); 100{binary} return make_BINARY(yytext, loc); 101[^ \t\n\"=]+ return yy::parser::make_NON_WS(yytext, loc); 102\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); } 103. { throw yy::parser::syntax_error(loc, "invalid character: " + std::string(yytext)); } 104} 105 106"/*" { BEGIN(c_comment); } 107"," return yy::parser::make_COMMA(loc); 108"::" return yy::parser::make_REVERSE(loc); 109":" return yy::parser::make_COLON(loc); 110"[" return yy::parser::make_LBRACKET(loc); 111"]" return yy::parser::make_RBRACKET(loc); 112"(" return yy::parser::make_LPAREN(loc); 113")" return yy::parser::make_RPAREN(loc); 114"+" return yy::parser::make_PLUS(loc); 115"--" return yy::parser::make_POST_DECREMENT(loc); 116"−−" return yy::parser::make_POST_DECREMENT(loc); 117"-" return yy::parser::make_MINUS(loc); 118"*" return yy::parser::make_MULTIPLY(loc); 119"/" return yy::parser::make_DIVIDE(loc); 120"|" return yy::parser::make_OR(loc); 121"&" return yy::parser::make_AND(loc); 122">>" return yy::parser::make_SHR(loc); 123"<<" return yy::parser::make_SHL(loc); 124"^" return yy::parser::make_XOR(loc); 125"!=" return yy::parser::make_NOT_EQUAL(loc); 126"!" return yy::parser::make_NOT(loc); 127"~" return yy::parser::make_NOT(loc); 128"<" return yy::parser::make_LESSTHAN(loc); 129 130".program" return yy::parser::make_PROGRAM(loc); 131".wrap_target" return yy::parser::make_WRAP_TARGET(loc); 132".wrap" return yy::parser::make_WRAP(loc); 133".word" return yy::parser::make_WORD(loc); 134".define" return yy::parser::make_DEFINE(loc); 135".side_set" return yy::parser::make_SIDE_SET(loc); 136".origin" return yy::parser::make_ORIGIN(loc); 137".lang_opt" { BEGIN(lang_opt); return yy::parser::make_LANG_OPT(loc); } 138".pio_version" return yy::parser::make_PIO_VERSION(loc); 139".clock_div" return yy::parser::make_CLOCK_DIV(loc); 140".fifo" return yy::parser::make_FIFO(loc); 141".mov_status" return yy::parser::make_MOV_STATUS(loc); 142".set" return yy::parser::make_DOT_SET(loc); 143".out" return yy::parser::make_DOT_OUT(loc); 144".in" return yy::parser::make_DOT_IN(loc); 145 146{directive} return yy::parser::make_UNKNOWN_DIRECTIVE(yytext, loc); 147 148"JMP" return yy::parser::make_JMP(loc); 149"WAIT" return yy::parser::make_WAIT(loc); 150"IN" return yy::parser::make_IN(loc); 151"OUT" return yy::parser::make_OUT(loc); 152"PUSH" return yy::parser::make_PUSH(loc); 153"PULL" return yy::parser::make_PULL(loc); 154"MOV" return yy::parser::make_MOV(loc); 155"IRQ" return yy::parser::make_IRQ(loc); 156"SET" return yy::parser::make_SET(loc); 157"NOP" return yy::parser::make_NOP(loc); 158 159"PUBLIC" return yy::parser::make_PUBLIC(loc); 160 161"OPTIONAL" return yy::parser::make_OPTIONAL(loc); 162"OPT" return yy::parser::make_OPTIONAL(loc); 163"SIDE" return yy::parser::make_SIDE(loc); 164"SIDESET" return yy::parser::make_SIDE(loc); 165"SIDE_SET" return yy::parser::make_SIDE(loc); 166"PIN" return yy::parser::make_PIN(loc); 167"GPIO" return yy::parser::make_GPIO(loc); 168"OSRE" return yy::parser::make_OSRE(loc); 169 170"PINS" return yy::parser::make_PINS(loc); 171"NULL" return yy::parser::make_NULL(loc); 172"PINDIRS" return yy::parser::make_PINDIRS(loc); 173"X" return yy::parser::make_X(loc); 174"Y" return yy::parser::make_Y(loc); 175"PC" return yy::parser::make_PC(loc); 176"EXEC" return yy::parser::make_EXEC(loc); 177"ISR" return yy::parser::make_ISR(loc); 178"OSR" return yy::parser::make_OSR(loc); 179"STATUS" return yy::parser::make_STATUS(loc); 180 181"BLOCK" return yy::parser::make_BLOCK(loc); 182"NOBLOCK" return yy::parser::make_NOBLOCK(loc); 183"IFFULL" return yy::parser::make_IFFULL(loc); 184"IFEMPTY" return yy::parser::make_IFEMPTY(loc); 185"REL" return yy::parser::make_REL(loc); 186 187"CLEAR" return yy::parser::make_CLEAR(loc); 188"NOWAIT" return yy::parser::make_NOWAIT(loc); 189"JMPPIN" return yy::parser::make_JMPPIN(loc); 190"NEXT" return yy::parser::make_NEXT(loc); 191"PREV" return yy::parser::make_PREV(loc); 192 193"TXRX" return yy::parser::make_TXRX(loc); 194"TX" return yy::parser::make_TX(loc); 195"RX" return yy::parser::make_RX(loc); 196"TXPUT" return yy::parser::make_TXPUT(loc); 197"TXGET" return yy::parser::make_TXGET(loc); 198"PUTGET" return yy::parser::make_PUTGET(loc); 199 200"ONE" return yy::parser::make_INT(1, loc); 201"ZERO" return yy::parser::make_INT(0, loc); 202 203"RP2040" return yy::parser::make_RP2040(loc); 204"RP2350" return yy::parser::make_RP2350(loc); 205"RXFIFO" return yy::parser::make_RXFIFO(loc); 206"TXFIFO" return yy::parser::make_TXFIFO(loc); 207 208"LEFT" return yy::parser::make_LEFT(loc); 209"RIGHT" return yy::parser::make_RIGHT(loc); 210"AUTO" return yy::parser::make_AUTO(loc); 211"MANUAL" return yy::parser::make_MANUAL(loc); 212<<EOF>> return yy::parser::make_END(loc); 213 214{int} return make_INT(yytext, loc); 215{float} return make_FLOAT(yytext, loc); 216{hex} return make_HEX(yytext, loc); 217{binary} return make_BINARY(yytext, loc); 218 219{id} return yy::parser::make_ID(yytext, loc); 220 221{comment} { } 222 223. { throw yy::parser::syntax_error(loc, "invalid character: " + std::string(yytext)); } 224 225%% 226 227yy::parser::symbol_type make_INT(const std::string &s, const yy::parser::location_type& loc) 228{ 229 errno = 0; 230 long n = strtol (s.c_str(), NULL, 10); 231 if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) 232 throw yy::parser::syntax_error (loc, "integer is out of range: " + s); 233 return yy::parser::make_INT((int) n, loc); 234} 235 236yy::parser::symbol_type make_FLOAT(const std::string &s, const yy::parser::location_type& loc) 237{ 238 errno = 0; 239 float n = strtof (s.c_str(), NULL); 240 return yy::parser::make_FLOAT(n, loc); 241} 242 243yy::parser::symbol_type make_HEX(const std::string &s, const yy::parser::location_type& loc) 244{ 245 errno = 0; 246 long n = strtol (s.c_str() + 2, NULL, 16); 247 if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) 248 throw yy::parser::syntax_error (loc, "hex is out of range: " + s); 249 return yy::parser::make_INT((int) n, loc); 250} 251 252yy::parser::symbol_type make_BINARY(const std::string &s, const yy::parser::location_type& loc) 253{ 254 errno = 0; 255 long n = strtol (s.c_str()+2, NULL, 2); 256 if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE)) 257 throw yy::parser::syntax_error (loc, "binary is out of range: " + s); 258 return yy::parser::make_INT((int) n, loc); 259} 260 261void pio_assembler::scan_begin () 262{ 263 yy_flex_debug = false; 264 if (source.empty () || source == "-") 265 yyin = stdin; 266 else if (!(yyin = fopen (source.c_str (), "r"))) 267 { 268 std::cerr << "cannot open " << source << ": " << strerror(errno) << '\n'; 269 exit (EXIT_FAILURE); 270 } 271} 272 273void pio_assembler::scan_end () 274{ 275 fclose (yyin); 276} 277