Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial commit

  • Loading branch information...
commit 75a8bc4e33824a4b60c066135a33ea08c7cf5c05 0 parents
@singpolyma authored
2  .gitignore
@@ -0,0 +1,2 @@
+*.o
+rpnr
13 COPYING
@@ -0,0 +1,13 @@
+Copyright (c) 2010, Stephen Paul Weber <singpolyma@singpolyma.net>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
4 Makefile
@@ -0,0 +1,4 @@
+.PHONY: all clean
+all: rpnr
+clean: rpnr
+ $(RM) $^
35 README
@@ -0,0 +1,35 @@
+= Reverse Polish Notation for Ruby =
+
+== Buiding ==
+
+You will need make, lex, and a C compiler.
+
+Run make
+
+== Running ==
+
+The rpnr utility takes RPNR on standard in and outputs valid Ruby on stanadard out.
+
+rpnr < code.rpnr > code.rb
+
+== RPNR Syntax ==
+
+* Tokens are seperated by whitespace
+* '(' and ')' are whitespace
+* Tokens that are all non-alphanumeric or start with a ':' are messages
+* Tokens in double quotes are strings.
+* Tokens in single quotes are symbols.
+* Tokens in /.*/ are regular expressions.
+* Tokens that are numbers are numbers
+
+When a non-message is encountered, it is pushed onto the stack.
+
+When a message is encountered:
+* The top two items are popped
+* The next-to-top item is passed the message with the argument being the top
+
+=== Edge cases ===
+
+'a,b' (a b +) :lambda #=> lambda{|a,b| a.send(:'+', b)}
+
+a 1 = #=> a = 1
62 rpnr-runtime.rb
@@ -0,0 +1,62 @@
+class NilClass
+ def +(b); b; end # Make + work with nil
+ def method_missing(name, *args)
+ [].send(name, *args) # Proxy nil onto []
+ rescue NoMethodError
+ super
+ end
+end
+
+# List building conveniance
+Object.send(:define_method, :',', lambda {|b| [self, b]})
+Array.send(:define_method, :',', lambda {|b| self + [b]})
+
+# Multiple operations as one expression conveniance (mostly for lambda)
+Object.send(:define_method, :';', lambda {|b| b })
+
+class Object
+ # Control flow as methods
+ def while(cond, block=nil)
+ while cond.is_a?(Proc) ? cond.call : cond
+ block && block.call
+ block_given? && yield
+ end
+ end
+ def until(cond, block=nil)
+ until cond.is_a?(Proc) ? cond.call : cond
+ block && block.call
+ block_given? && yield
+ end
+ end
+ def if(cond, block_if_true=nil, block_if_false=nil)
+ if cond.is_a?(Proc) ? cond.call : cond
+ block_if_true && block_if_true.call
+ else
+ block_if_false && block_if_false.call
+ end
+ end
+ def unless(cond, block_if_true=nil, block_if_false=nil)
+ unless cond.is_a?(Proc) ? cond.call : cond
+ block_if_true && block_if_true.call
+ else
+ block_if_false && block_if_false.call
+ end
+ end
+
+ # Output conveniance
+ def puts
+ Kernel::puts(to_s)
+ end
+
+ # Handle multiple-airity methods being passed a list magically
+ def magic_send(message, arg)
+ arity = method(message).arity
+ if arity < 1
+ send(message)
+ elsif arg.is_a?(Array) && arity > 1
+ send(message, *arg)
+ else
+ send(message, arg)
+ end
+ end
+end
98 rpnr.l
@@ -0,0 +1,98 @@
+%{
+#include <stdio.h>
+#define HANDLE_FATAL(x) do { if(!(x)) { fputs("A fatal error occured.\n", stderr); abort(); } } while (0) /* Simple error handling */
+/* Global stack */
+size_t stack_size = 0;
+size_t stack_length = 0;
+char **stack = NULL;
+/* Function prototypes */
+void push(const char *);
+void do_message(const char *);
+%}
+%%
+
+:[^ \t\r\n\(\)]+|[^0-9a-zA-Z \t\r\n\(\)]+ { do_message(yytext); }
+\/[^\/]+\/|'[^']+'|\"[^\"]+\"|[^ \t\r\n\(\)]+ { push(yytext); }
+[ \t\r\n\(\)] ; /* ignore whitespace */
+
+%%
+/* Push a string onto the global stack */
+void push(const char *item) {
+ char *s;
+ if(item[0] == '\'') { /* symbol, prepend ':' */
+ HANDLE_FATAL(s = malloc((strlen(item)+1+1)*sizeof(*s)));
+ s[0] = ':';
+ s[1] = '\0';
+ } else {
+ HANDLE_FATAL(s = malloc((strlen(item)+1)*sizeof(*s)));
+ s[0] = '\0';
+ }
+ strcat(s, item);
+ if(stack_length == stack_size) { /* Stack is full, enlarge */
+ stack_size = (stack_size+1)*2;
+ HANDLE_FATAL(stack = realloc(stack, stack_size*sizeof(*stack)));
+ }
+ stack[stack_length++] = s; /* Push s on as new last element */
+}
+
+/* Pop element off the global stack */
+char *pop() {
+ return stack[--stack_length];
+}
+
+/* Process a "message" by popping top two elements and pushing the result */
+void do_message(const char *message) {
+ char *arg = pop();
+ char *obj = pop();
+ if(strcmp(message, "=") == 0 || strcmp(message, ":=") == 0) { /* Assignment (special case) */
+ HANDLE_FATAL(obj = realloc(obj, (strlen(obj)+strlen("=()")+strlen(arg)+1)*sizeof(*obj)));
+ strcat(obj, "=(");
+ strcat(obj, arg);
+ strcat(obj, ")");
+ push(obj);
+ } else if(strcmp(message, ":lambda") == 0) { /* Lambda (special case) */
+ if(obj[0] == ':') { /* Handle case where arguments are a symbol and push() has prepended : */
+ obj[1] = '|';
+ } else {
+ obj[0] = '|';
+ }
+ obj[strlen(obj)-1] = '|';
+ HANDLE_FATAL(obj = realloc(obj, (strlen(obj)+strlen("lambda{ }")+strlen(arg)+1)*sizeof(*obj)));
+ memmove(obj+strlen("lambda{")-(obj[0] == ':'), obj, strlen(obj));
+ strcpy(obj, "lambda");
+ obj[6] = '{';
+ strcat(obj, " ");
+ strcat(obj, arg);
+ strcat(obj, "}");
+ push(obj);
+ } else {
+ HANDLE_FATAL(obj = realloc(obj, (strlen(obj)+strlen("().magic_send(,())")+strlen(":''")+strlen(message)+strlen(arg)+1)*sizeof(*obj)));
+ memmove(obj+1, obj, strlen(obj));
+ obj[0] = '(';
+ strcat(obj, ").magic_send(");
+ if(message[0] != ':') strcat(obj, ":'");
+ strcat(obj, message);
+ if(message[0] != ':') strcat(obj, "'");
+ strcat(obj, ",(");
+ strcat(obj, arg);
+ strcat(obj, "))");
+ free(arg);
+ push(obj);
+ }
+}
+
+int yywrap() { return 1; }
+int main(void) {
+ int r;
+ size_t i;
+ if((r = yylex())) {
+ fputs("A lexing error occured. Check your input.\n", stderr);
+ return r;
+ }
+ puts("#!/usr/bin/ruby");
+ puts("require 'rpnr-runtime'");
+ for(i = 0; i < stack_length; i++) {
+ puts(stack[i]);
+ }
+ return r;
+}
Please sign in to comment.
Something went wrong with that request. Please try again.