Skip to content
Snippets Groups Projects
Select Git revision
1 result Searching

disable_sleep.pp

Blame
  • Grammar_parser.pmod NaN GiB
    #!/usr/local/bin/pike
    
    /*
     * $Id: Grammar_parser.pmod,v 1.6 1998/06/24 16:44:13 grubba Exp $
     *
     * Generates a parser from a textual specification.
     *
     * Henrik Grubbstrm 1996-12-06
     */
    
    //.
    //. File:	Grammar_parser.pmod
    //. RCSID:	$Id: Grammar_parser.pmod,v 1.6 1998/06/24 16:44:13 grubba Exp $
    //. Author:	Henrik grubbstrm (grubba@infovav.se)
    //.
    //. Synopsis:	Generates an LR parser from a textual specification.
    //.
    //. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //.
    //. This module generates an LR parser from a grammar specified according
    //. to the following grammar:
    //.
    //.        directives : directive ;
    //.	   directives : directives directive ;
    //.	   directive : declaration ;
    //.	   directive : rule ;
    //.	   declaration : "%token" terminals ";" ;
    //.	   rule : nonterminal ":" symbols ";" ;
    //.	   rule : nonterminal ":" symbols action ";" ;
    //.	   symbols : symbol ;
    //.	   symbols : symbols symbol ;
    //.	   terminals : terminal ;
    //.	   terminals : terminals terminal ;
    //.	   symbol : nonterminal ;
    //.	   symbol : "string" ;
    //.	   action : "{" "identifier" "}" ;
    //.	   nonterminal : "identifier" ;
    //.	   terminal : "string";
    //.
    
    /*
     * Includes
     */
    
    #include <stdio.h>
    
    /*
     * Defines
     */
    
    /* #define DEBUG */
    
    /* Errors during parsing */
    /* Action for rule is missing from master object */
    #define ERROR_MISSING_ACTION	256
    /* Action for rule is not a function */
    #define ERROR_BAD_ACTION	512
    
    import LR;
    
    static private object(parser) _parser = parser();
    
    /*
     * Scanner
     */
    
    static private class scan {
      string str = "";
      int pos;
    
      array|string scan()
      {
        while (1) {
          if (pos >= sizeof(str)) {
    	/* EOF */
    	return("");
          } else {
    	int start=pos++;
    	switch (str[start]) {
    	case '%':
    	  /* Token */
    	  while ((pos < sizeof(str)) &&
    		 ((('A' <= str[pos]) && ('Z' >= str[pos])) ||
    		  (('a' <= str[pos]) && ('z' >= str[pos])))) {
    	    pos++;
    	  }
    	  return (lower_case(str[start..pos-1]));
    	case '\"':
    	  /* String */
    	  while ((pos < sizeof(str)) &&
    		 (str[pos] != '\"')) {
    	    if (str[pos] == '\\') {
    	      pos++;
    	    }
    	    pos++;
    	  }
    	  if (pos < sizeof(str)) {
    	    pos++;
    	  } else {
    	    pos = sizeof(str);
    	  }
    	  if (str != pos-2) {
    	    return ({ "string", str[start+1..pos-2] });
    	  }
    	  /* Throw away empty strings (EOF) */
    	  break;
    	case '/':
    	  /* Comment */
    	  if (str[pos] != '*') {
    	    werror(sprintf("Bad token \"/%c\" in input\n", str[pos]));
    	    break;
    	  }
    	  pos++;
    	  while (1) {
    	    if ((++pos >= sizeof(str)) ||
    		(str[pos-1 .. pos] == "*/")) {
    	      pos++;
    	      break;
    	    }
    	  }
    	  break;
    	case '(':
    	  return("(");
    	case ')':
    	  return(")");
    	case '{':
    	  return("{");
    	case '}':
    	  return("}");
    	case ':':
    	  return(":");
    	case ';':
    	  return(";");
    	case '\n': 
    	case '\r':
    	case ' ':
    	case '\t':
    	  /* Whitespace */
    	  break;
    	case '0'..'9':
    	  /* int */
    	  while ((pos < sizeof(str)) &&
    		 ('0' <= str[pos]) && ('9' >= str[pos])) {
    	    pos++;
    	  }
    	  return (({ "int", (int)str[start .. pos-1] }));
    	default:
    	  /* Identifier */
    	  while ((pos < sizeof(str)) &&
    		 ((('A' <= str[pos]) && ('Z' >= str[pos])) ||
    		  (('a' <= str[pos]) && ('z' >= str[pos])) ||
    		  (('0' <= str[pos]) && ('9' >= str[pos])) ||
    		  ('_' == str[pos]) || (str[pos] >= 128))) {
    	    pos++;
    	  }
    	  return (({ "identifier", str[start .. pos-1] }));
    	}
          }
        }
      }
    }
    
    static private object(scan) scanner = scan();
    
    static private array(string) nonterminals = ({
      "translation_unit",
      "directives",
      "directive",
      "declaration",
      "rule",
      "symbols",
      "terminals",
      "symbol",
      "action",
      "nonterminal",
      "terminal",
      "priority",
    });
    
    static private object(Stack.stack) id_stack = Stack.stack();
    
    static private mapping(string:int) nonterminal_lookup = ([]);
    
    static private object(parser) g;
    
    static private object master;
    
    //. + error
    //.   Error code from the parsing.
    int error;
    
    static private int add_nonterminal(string id)
    {
      int nt = nonterminal_lookup[id];
    
      if (!nt) {
        nt = nonterminal_lookup[id] = id_stack->ptr;
        id_stack->push(id);
      }
      return(nt);
    }
    
    static private void add_tokens(array(string) tokens)
    {
      /* NOOP */
    #if 0
      if (sizeof(tokens)) {
        map(tokens, add_token);
      }
    #endif /* 0 */
    }
    
    static private void set_left_tokens(string ignore, int pri_val, array(string) tokens)
    {
      foreach (tokens, string token) {
        g->set_associativity(token, -1);	/* Left associative */
        g->set_priority(token, pri_val);
      }
    }
    
    static private string internal_symbol_to_string(int|string symbol)
    {
      if (intp(symbol)) {
        return (nonterminals[symbol]);
      } else {
        return ("\"" + symbol + "\"");
      }
    }
    
    static private string symbol_to_string(int|string symbol)
    {
      if (intp(symbol)) {
        if (symbol < id_stack->ptr) {
          return (id_stack->arr[symbol]);
        } else {
          /* Only happens with the initial(automatic) rule */
          return ("nonterminal"+symbol);
        }
      } else {
        return ("\""+symbol+"\"");
      }
    }
    
    static private void add_rule(int nt, string colon, array(mixed) symbols, string action)
    {
      if (action == ";") {
        action = 0;
      }
      if ((action) && (master)) {
        if (!master[action]) {
          werror(sprintf("Warning: Missing action %s\n", action));
    
          error |= ERROR_MISSING_ACTION;
        } else if (!functionp(master[action])) {
          werror(sprintf("Warning: \"%s\" is not a function in object\n",
    		     action));
          
          error |= ERROR_BAD_ACTION;
        } else {
          g->add_rule(rule(nt, symbols, master[action]));
          return;
        }
      }
      g->add_rule(rule(nt, symbols, action));
    }
    
    void create()
    {
      _parser->set_symbol_to_string(internal_symbol_to_string);
    
      _parser->verbose = 0;
    
      _parser->add_rule(rule(0, ({ 1, "" }), 0));		/* translation_unit */
      _parser->add_rule(rule(1, ({ 2 }), 0));		/* directives */
      _parser->add_rule(rule(1, ({ 1, 2 }), 0));		/* directives */
      _parser->add_rule(rule(2, ({ 3 }), 0));		/* directive */
      _parser->add_rule(rule(2, ({ 4 }), 0));		/* directive */
      _parser->add_rule(rule(3, ({ "%token", 6, ";" }),
    			 add_tokens));			/* declaration */
      _parser->add_rule(rule(3, ({ "%left", 11, 6, ";" }),
    			 set_left_tokens));		/* declaration */
      _parser->add_rule(rule(4, ({ 9, ":", 5, ";" }),
    			 add_rule));			/* rule */
      _parser->add_rule(rule(4, ({ 9, ":", 5, 8, ";" }),
    			 add_rule));			/* rule */
      _parser->add_rule(rule(5, ({}),
    			 lambda () {
    			   return ({}); } ));		/* symbols */
      _parser->add_rule(rule(5, ({ 5, 7 }),
    			 lambda (array x, mixed|void y) {
    			   if (y) { return (x + ({ y })); }
    			   else { return (x); }} ));	/* symbols */
      _parser->add_rule(rule(6, ({ 10 }),
    			 lambda (string x) {
    			   return ({ x }); } ));	/* terminals */
      _parser->add_rule(rule(6, ({ 6, 10 }),
    			 lambda (array(string) x, string y) {
    			   return (x + ({ y })); } ));	/* terminals */
      _parser->add_rule(rule(7, ({ 9 }), 0 ));		/* symbol */
      _parser->add_rule(rule(7, ({ 10 }), 0 ));		/* symbol */
      _parser->add_rule(rule(8, ({ "{", "identifier", "}" }),
    			 lambda (mixed brace_l, string id, mixed brace_r) {
    			   return (id); } ));		/* action */
      _parser->add_rule(rule(8, ({ "{", "string", "}" }),
    			 lambda (mixed brace_l, string str, mixed brace_r) {
    			   werror(sprintf("Warning: Converting string \"%s\" "
    					  "to identifier\n", str));
    			   return(str); } ));		/* action */
      _parser->add_rule(rule(9, ({ "identifier" }),
    			 add_nonterminal));		/* nonterminal */
      _parser->add_rule(rule(10, ({ "string" }), 0));	/* terminal */
      _parser->add_rule(rule(11, ({ "(", "int", ")" }),
    			 lambda (mixed paren_l, int val, mixed paren_r) {
    			   return (val);
    			 } ));				/* priority */
      _parser->add_rule(rule(11, ({}), 0));			/* priority */
    
      _parser->compile();
    }
    
    //. - make_parser
    //.
    //. Compiles the parser-specification given in the first argument.
    //. Named actions are taken from the object if available, otherwise
    //. left as is.
    //.
    //. BUGS: Returns error-code in both Grammar_parser.error and
    //. return_value->error.
    object(parser) make_parser(string str, object|void m)
    {
      object(parser) res = 0;
    
      master = m;
      error = 0;	/* No errors yet */
    
      g = parser();
    
      scanner->str = str;
      scanner->pos = 0;
    
      g->set_symbol_to_string(symbol_to_string);
    
      id_stack = Stack.stack();
    
      nonterminal_lookup = ([]);
    
    #ifdef DEBUG
      _parser->verbose = 1;
      g->verbose = 1;
    #else
      g->verbose = 0;
    #endif /* DEBUG */
    
      /* Default rule -- Will never be reduced */
      id_stack->push("Translation Unit");	/* Nonterminal #0 -- Start symbol */
      g->add_rule(rule(0, ({ 1, "" }), 0));	/* Rule #0 -- Start rule */
    
      _parser->parse(scanner->scan);
    
      if ((!_parser->error) &&
          (!error) &&
          (!g->compile())) {
        res = g;
      }
    
      g = 0;	/* Don't keep any references */
    
      return (res);
    }
    
    //. - make_parser_from_file
    //.
    //. Compiles the file specified in the first argument into an LR parser.
    //.
    //. SEE ALSO: Grammar_parser.make_parser
    int|object(parser) make_parser_from_file(string fname, object|void m)
    {
      object(Stdio.File) f = Stdio.File();
      int|object(parser) g = 0;
      if (f->open(fname, "r")) {
        g = make_parser(f->read(0x7fffffff), m);
        f->close();
      }
      return(g);
    }
    
    /*
     * Syntax-checks and compiles the grammar files
     */
    int main(int argc, string *argv)
    {
      if (argc == 1) {
        werror(sprintf("Usage:\n\t%s <files>\n", argv[0]));
      } else {
        int i;
    
        for (i=1; i < argc; i++) {
          werror(sprintf("Compiling \"%s\"...\n", argv[i]));
    
          int|object(parser) g = make_parser_from_file(argv[i]);
          if (error || !g) {
    	werror("Compilation failed\n");
          } else {
    	werror("Compilation done\n");
          }
        }
      }
    }