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