Mercurial > ~dholland > hg > ag > index.cgi
diff examples/rcalc/rcalc.syn @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/rcalc/rcalc.syn Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,227 @@ +{/* + * AnaGram, a System for Syntax Directed Parsing + * RCALC.SYN: A Roman Numeral Calculator Example + * + * Copyright MCMXCIII, MCMXCVI, Parsifal Software. All Rights Reserved. + * Copyright MMVII David A. Holland. 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. + */} + +c = 'c' +d = 'd' +i = 'i' +l = 'l' +m = 'm' +v = 'v' +x = 'x' + +eof = 0 + '\n' // Input is a one-line string + +ws = ' ' + '\t' + '\r' // Blanks, tabs, and stray CRs + +[ + ~allow macros // Simplify debugging + disregard ws // Ignore blanks and tabs + lexeme { roman numeral} // No blanks inside a number + ~case sensitive // Allow upper/lower input + context type = int // Track context + default token type = long // All arithmetic uses longs + pointer input // Input is array in memory +] + + +// Grammar definition + +(void) calculation $ + -> expression:x, eof =print_roman(x); + + +// Expression logic + +expression + -> term // Value of expression is value of term + -> expression:x, '+', term:y =x+y; + -> expression:x, '-', term:y =x-y; + +term + -> factor // Value of term is value of factor + -> term:x, '*', factor:y =x*y; + -> term:x, '/', factor:y =y ? x/y : divide_error(RULE_CONTEXT[2]); + +factor + -> roman numeral // Value of factor is value of roman numeral + -> "nihil" =0; + -> '(', expression:x, ')' =x; + -> '-', factor:x =-x; + + +// Roman Numeral Syntax + +roman numeral + -> thousands:x, hundreds?:y =x+y; + -> hundreds // Value of roman numeral is value of hundreds + +thousands + -> m =1000; + -> thousands:x, m =x+1000; + +hundreds + -> hundreds field:x, tens?:y =x+y; + -> tens // Value of hundreds is value of tens + +hundreds field + -> c, m =900; + -> c, d =400; + -> count hundreds + +count hundreds + -> c =100; + -> d =500; + -> count hundreds:x, c =x+100; + +tens + -> tens field:x, units?:y =x+y; + -> units // Value of tens is value of units + +tens field + -> x, m =990; + -> x, d =490; + -> x, c =90; + -> x, l =40; + -> count tens + +count tens + -> x =10; + -> l =50; + -> count tens:x, x =x+10; + +units + -> i, m =999; + -> i, d =499; + -> i, c =99; + -> i, l =49; + -> i, x =9; + -> i, v =4; + -> count units // Value of "units" is value of "count units" + +count units + -> i =1; + -> v =5; + -> count units:x, i =x+1; + + +{ /* Embedded C */ +#include <stdio.h> + + +/* Macro Definitions */ + +#define GET_CONTEXT CONTEXT = PCB.column +#define SYNTAX_ERROR syntax_error() + +int semantic_error = 0; /* Divide by zero flag */ + + +/* + +syntax_error() positions a '^' character under the input line at the +point where the syntax error was discovered and then writes the error +message. + +*/ + +void syntax_error(void) { + int k = PCB.column; + while (k-- > 0) putchar(' '); + printf("^? %s\n","ERRARE HUMANUM EST\n"); +} + + +/* + +divide_error() is called when an attempt is made to divide by zero. The +entire divisor is marked with '^' characters. "semantic_error" is set +in order to disable printing of a result. + +*/ + +int divide_error(int cn) { + int k = PCB.column - cn; + while (cn--) putchar(' '); + while (k--) putchar('^'); + puts(" DIVISOR NIHIL EST"); + semantic_error = 1; + return 0; +} + + +/* + +print_roman() prints a signed integer in upper case Roman numerals. + +*/ + +void print_roman(long k) { + if (semantic_error) { + semantic_error = 0; + return; + } + printf(" = "); + if (k == 0) {printf("NIHIL\n"); return;} + + if (k < 0) putchar('-'), k=-k; + + while (k >= 1000) putchar('M'), k-=1000; + + if (k >= 900) printf("CM"), k-=900; + if (k >= 500) putchar('D'), k-=500; + if (k >= 400) printf("CD"), k-=400; + + while (k >= 100) putchar('C'), k-=100; + + if (k >= 90) printf("XC"), k-=90; + if (k >= 50) putchar('L'), k-=50; + if (k >= 40) printf("XL"), k-=40; + + while (k >= 10) putchar('X'), k-=10; + + if (k >= 9) printf("IX"), k -= 9; + if (k >= 5) putchar('V'), k-=5; + if (k >= 4) printf("IV"), k-=4; + + while (k >= 1) putchar('I'), k--; + + putchar('\n'); +} + + +/* Main Program -- reads a line from stdin and calls parser */ + +int main(void) { + char line[1024]; + while (1) { + printf("#"); + fflush(stdout); + if (fgets(line, sizeof(line), stdin) == NULL) break; + rcalc_pcb.pointer = (unsigned char *) line; + rcalc(); + } + return 0; +} + +} // End of Embedded C