Mercurial > ~dholland > hg > ag > index.cgi
diff tests/agcl/oldagsrc/rcalcx.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/tests/agcl/oldagsrc/rcalcx.syn Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,230 @@ +{/* +AnaGram, a System for Syntax Directed Parsing +RCALC.SYN: A Roman Numeral Calculator Example + +Copyright (c) MCMXCIII, MCMXCVI, Parsifal Software. +All Rights Reserved. +*/} + +c = 'c' +d = 'd' +i = 'i' +l = 'l' +m = 'm' +v = 'v' +x = 'x' + +eof = 0 // Input is a string + +ws = ' ' + '\t' // Blanks and tabs + +[ + ~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 + reentrant parser + parser file name = "#.cpp" +] + + +// Grammar definition + +(void) calculation $ + -> expression:x, eof =PCB.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 : PCB.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; + -> thousands + -> 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; + -> hundreds field + -> 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; + -> tens field + -> 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> + +#define PCB_TYPE Parser + +class Parser : public rcalcx_pcb_type { + int semantic_error; +public: + Parser() {} + void parse(char *); + void syntax_error(); + int divide_error(int cn); + void print_roman(long k); +}; + + +void Parser::parse(char *text) { + pointer = (unsigned char *) text; + semantic_error = 0; + rcalcx(this); +} + +/* Macro Definitions */ + +#define GET_CONTEXT CONTEXT = PCB.column +#define SYNTAX_ERROR PCB.syntax_error() + +/* + +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 Parser::syntax_error() { + int k = 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 Parser::divide_error(int cn) { + int k = 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 Parser::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[82]; + while (1) { + Parser pcb; + printf("#"); + if (gets(line) == NULL) break; + pcb.parse(line); + } + return 0; +} + +} // End of Embedded C