Mercurial > ~dholland > hg > ag > index.cgi
view examples/mpp/ex.syn @ 7:57b2cc9b87f7
Use memcpy instead of strncpy when we know the length anyway.
Modern gcc seems to think it knows how to detect misuse of strncpy,
but it's wrong (in fact: very, very wrong) and the path of least
resistance is to not try to fight with it.
author | David A. Holland |
---|---|
date | Mon, 30 May 2022 23:47:52 -0400 |
parents | 13d2b8934445 |
children |
line wrap: on
line source
{ /* * AnaGram, a System for Syntax Directed Programming * C Macro preprocessor * Constant Expression Evaluator Module * * Copyright 1993-2000 Parsifal Software. All Rights Reserved. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include "mpp.h" } [ //far tables // uncomment for 16 bit environment ~allow macros line numbers //escape backslashes // uncomment if using MSVC++ default token type = long default input type = token ~declare pcb ~diagnose errors error trace event driven input values ~test range ~lines and columns enum { eof =0, SPACE =' ', ANDAND ='A', // "&&" ANDassign, // "&=" ARROW, // "->" CONCAT, // "##" DECR, // "--" DIVassign, // "/=" ELLIPSIS, // "..." EQ, // "==" ERassign, // "^=" GE, // ">=" ICR, // "++" LE, // "<=" LS, // "<<" LSassign, // "<<=" MODassign, // "%=" MINUSassign, // "-=" MULTassign, // "*=" NE, // "!=" ORassign, // "|=" OROR, // "||" PLUSassign, // "+=" RS, // ">>" RSassign, // ">>=" CHARACTERconstant, // character constant STRINGliteral, // character string HEXconstant =129, OCTconstant, DECconstant, FLOATconstant, // real NAME, AUTO, // "auto" BREAK, // "break" CASE, // "case" CHAR, // "char" CONSTANT, // "const" CONTINUE, // "continue" DEFAULT, // "default" DO, // "do" DOUBLE, // "double" ELSE, // "else" ENUM, // "enum" EXTERN, // "extern" FLOAT, // "float" FOR, // "for" GOTO, // "goto" IF, // "if" INT, // "int" LONG, // "long" REGISTER, // "register" RETURN, // "return" SHORT, // "short" SIGNED, // "signed" SIZEOF, // "sizeof" STATIC, // "static" STRUCT, // "struct" SWITCH, // "switch" TYPEDEF, // "typedef" UNION, // "union" UNSIGNED, // "unsigned" VOIDkey, // "void" VOLATILE, // "volatile" WHILE, // "while" UNRECOGNIZED, } parser file name = "#.cpp" ] expression evaluator $ -> exp, eof exp -> conditional exp conditional exp -> logical or exp -> logical or exp:c, '?', conditional exp:x, ':', conditional exp:y = c != 0 ? x : y; logical or exp -> logical and exp -> logical or exp:x, OROR, logical and exp:y =x != 0 || y!=0; logical and exp -> inclusive or exp -> logical and exp:x, ANDAND, inclusive or exp:y =x != 0 && y !=0; inclusive or exp -> exclusive or exp -> inclusive or exp:x, '|', exclusive or exp:y =x | y; exclusive or exp -> and exp -> exclusive or exp:x, '^', and exp:y =x ^ y; and exp -> equality exp -> and exp:x, '&', equality exp:y =x & y; equality exp -> relational exp -> equality exp:x, EQ, relational exp:y =x == y; -> equality exp:x, NE, relational exp:y =x != y; relational exp -> shift exp -> relational exp:x, '<', shift exp:y =x < y; -> relational exp:x, '>', shift exp:y =x > y; -> relational exp:x, LE, shift exp:y =x <= y; -> relational exp:x, GE, shift exp:y =x >= y; shift exp -> additive exp -> shift exp:x, LS, additive exp:y =x << y; -> shift exp:x, RS, additive exp:y =x >> y; additive exp -> multiplicative exp -> additive exp:x, '+', multiplicative exp:y =x + y; -> additive exp:x, '-', multiplicative exp:y =x - y; multiplicative exp -> unary exp -> multiplicative exp:x, '*', unary exp:y =x * y; -> multiplicative exp:x, '/', nonzero:y =x / y; -> multiplicative exp:x, '%', nonzero:y =x % y; nonzero -> unary exp: x ={ if (x != 0) return x; syntax_error("Divide by Zero"); PCB.exit_flag = 5; return x; } unary exp -> primary exp -> '+', unary exp:x = x; -> '-', unary exp:x = -x; -> '~', unary exp:x = ~x; -> '!', unary exp:x = !x; primary exp -> HEXconstant:x =decode("%lx",x.handle); -> OCTconstant:x =decode("%lo",x.handle); -> DECconstant:x =decode("%ld",x.handle); -> CHARACTERconstant:x =decode("'%lc'",x.handle); -> NAME =0; -> '(', conditional exp:x, ')' =x; { // Embedded C #include <stdio.h> // Macro Definitions #define PCB (*ex_pcb) #define SYNTAX_ERROR syntax_error("Syntax error in constant expression"); // Static data static ex_pcb_type *ex_pcb; // Pointer to active pcb /* decode() is a simple function to recover the numeric value of a token. Its task is somewhat simplified by the fact that the only values allowed in this example are longs. */ static long decode(const char *fmt, unsigned ndx) { long v; sscanf(td[ndx], fmt, &v); return v; } // Members of expression_evaluator Class // Constructor /* Each expression_evaluator has its own parser control block. Therefore, before calling ex() or its initializer init_ex() it is necessary to make sure the pcb pointer for ex() is correctly set. */ expression_evaluator::expression_evaluator() { ex_pcb = &pcb; // set up pointer to pcb init_ex(); // init parser } // Reset expression_evaluator token_sink& reset(expression_evaluator &x) { ex_pcb = &x.pcb; // set up pointer to pcb init_ex(); // init parser return x; } // Xmit Token to expression_evaluator /* There could be space tokens in the input to the expression evaluator, but they are never significant so it is acceptable to filter them out on input. If the expression_evaluator has encountered an error, there is no point in giving it any further input. Otherwise, the input_code and input_value fields of the pcb are set up, the pcb pointer for ex is set, and ex() is called to deal with the token. When looping, it is only necessary to set up ex_pcb at the beginning of the loop. */ token_sink& expression_evaluator::operator << (token t) { if (t.id == SPACE || pcb.exit_flag != AG_RUNNING_CODE) return *this; pcb.input_code = t.id; pcb.input_value = t; ex_pcb = &pcb; ex(); return *this; } token_sink &expression_evaluator::operator << (token *tp) { ex_pcb = &pcb; while (pcb.exit_flag == AG_RUNNING_CODE) { if (pcb.input_code == SPACE) continue; pcb.input_code = tp->id; pcb.input_value = *tp++; ex(); } return *this; } // Return Value of expression_evaluator /* The (long) cast operator is overloaded to provide a mechanism to retrieve the value of the expression evaluated by the expression_evaluator. If there was a syntax error, the return value is zero. */ expression_evaluator::operator long() { ex_pcb = &pcb; if (pcb.exit_flag == AG_SUCCESS_CODE) return ex_value(); else return 0; } /* // Check expression_evaluator for error int error(expression_evaluator &x) { return x.pcb.exit_flag != AG_SUCCESS_CODE; } */ } // End of Embedded C