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