Spacecase

Spacecase is a simple Java-like language which provides total whitespace neutrality while remaining relatively usable. It was written by an angsty Python developer about five minutes ago after hearing yet another inane argument over whether whitespace significance was a valid language construct.

Elimination of Whitespace Significance
After some brief analysis, she concluded that every major programming language relies on whitespace very heavily, to separate tokens. In a flash of inspiration, she realized this could be overcome simply by making a few changes to a C-like grammar.

Problem One: Comments
So-called "C++ style" comments rely on whitespace (specifically, a newline) to terminate them: // C++ style comment

"C style" comments, however, do not, so they are used in Spacecase: /* C style comment */

Problem Two: Identifiers
This was the bigger problem. In most languages, Identifiers are essentially defined by the following BNFish grammar: identifier ::= [A-Za-z_] [A-Za-z0-9_]*

Meaning one alpha character (or an underscore) followed by zero or more alphanumeric characters and/or underscores. This relaxed definition means whitespace must be relied upon for tokenizing. Here's a snippet of C code that relies on whitespace:

else if (a == b) { g; }

If the whitespace were completely stripped, this would produce: elseif(a==b){g;} and elseif is not a valid C keyword. Spacecase addresses this issue by forcing identifiers into a slightly stricter definition:

identifier ::= [A-Z] [a-z_]*

In other words, identifiers MUST consist of at least one UPPERCASE letter followed optionally by LOWERCASE letters and/or underscores. This makes a number of identifier styles invalid:


 * camelCase
 * PascalCase
 * all_lowercase
 * ALL_UPPERCASE
 * Var2 (no digits allowed -- why is explained later)

This creates the need for a special style, which I have lovingly dubbed...


 * Space_case

Now, of course, the seasoned C programmer will tell me this would suffice: else{ if (a == b) { g; }}

but:
 * 1) That's ugly
 * 2) Stay tuned for...

Problem Three: String Literals
This is the big one. Strings often contain spaces. Here's an example of a simple C++ program that relies on whitespace significance inside strings, as well as a few other places:

using namespace std; /* usingnamespacestd ?? wow */ int main /* would become "intmain" without spaces. Uh oh! */ {   // this comment would screw up the whole rest of the program cout << "Hello World" << endl; /* "HelloWorld" would be output if not for the space in the string */ return 0; /* return0 = fail */ }
 * 1) include /* Note: this line also poses a problem. Tsk! */

Solution: Since every other whitespace character has a well-known string escape, we'll add one for spaces: "\s".

Problem Four: Number Literals
This issue is pretty obvious. Example C code: return 0;

This is why digits aren't allowed in identifiers at all. Spacecase: Return 0;

If this were glommed together, it could still be read as Spacecase code, since "Return0" is not a valid Spacecase identifier (see Problem Two).

Putting It All Together: Spacecase Example
So here's an example of a simple Spacecase program (Hello World):

Import Stdio;

Int Main( String[] Args ) {   Stdio.Writeln("Hello\sWorld!"); Return 0; }

And the best part? It's completely whitespace-neutral, so we can just strip all the spaces out of it and get a functional (but very ugly) program:

ImportStdio;IntMain(String[]Args){Stdio.Output("Hello\sWorld!\n");Return0;}

Stringspace "Cheat"
And since the only really painful part of this code is the whole "\s" thing, I've generously included a special directive for enabling string spaces ("Import Stringspace"):

Import Stringspace; Import Stdio; Int Main( String[] Args ) {   Stdio.Writeln("Hello World"); Return 0; }

Full-Blown Example
This program represents a postfix expression evaluator.

Example 1
This computes the sum of squares of A and B, (A * A) + (B * B): AA*BB*+

Example 2
Infix: 4 * ((1 + 9) - (8 / 2)) Postfix: 419+82/-*

Program
/* Java-style package declaration */ Package Org.Esolangs.Examples.Postfix_interpreter; /* libraries we need */ Import Stdio; Import Collections; /* Yay, object-oriented design! */ Public Class Postfix_interpreter {    /* constants that define behavior of valid characters */ Const String Number_chars = "0123456789"; Const String Math_chars = "+-*/"; Const String Valid_chars = Number_chars + Math_chars; /* instance variables */ Collections.Stack Stack; Collections.Queue Queue; /* constructors */ Public Postfix_interpreter {        Initialize; }    /* public methods */ Public Void Initialize {        Stack = Collections.Stack; Queue = Collections.Queue; }    Public Int Interpret( String Input ) {        Fill_queue( Input ); Try {            /** just to show off the While block ** While ( Queue.Length > 0 ) {                String Op = Queue.Get; Handle_op( Op ); }            ***************************************/             /* better way to do it: */ Foreach (String Op In Queue) {                Handle_op( Op ); }            /* save result: */ Output = Queue.Pop; }        Catch DivideByZeroError Err {            /* user sucks at math */ Stdio.Stderr.Writeln( "Invalid\sinput\sprovided,\sresulting\sin\s(undefined)                \sdivision\sby\szero." ); /* showing off whitespace ignorance in String literals */ Output = Int.Undefined; }        Catch Exception Exc {            /* something else went wrong, probably a stack underflow */ Stdio.Stderr.Writeln( "Error\soccurred:\s" + Exc.To_string ); Output = Int.Undefined; }        Finally {            /* clean up */ Initialize; }        Return Output; }    /* internal methods */ Private Void Fill_queue( String Input ) {        For (Int I = Input.Length - 1; I >= 0; I--) {            Queue.Put( Input[I] ); }    }     Private Void Handle_op( String Op ) {        If ( Not Op In Valid_chars ) {            Return; }        Else If ( Op In Number_chars ) {            Handle_number( Op ); }        Else /* Op In Math_chars */ {            Handle_math( Op ); }        Return; }    Private Void Handle_number( String Op ) {        Int Num = Number_chars.Find( Op ); Stack.Push( Num ); }    Private Void Handle_math( String Op ) {        Int Right_operand = Stack.Pop; Int Left_operand = Stack.Pop; Switch ( Op ) {        Case '+': Stack.Push( Left_operand + Right_operand ); Break; Case '-': Stack.Push( Left_operand - Right_operand ); Break; Case '*': Stack.Push( Left_operand * Right_operand ); Break; Case '/': Stack.Push( Left_operand / Right_operand ); Break; }        Return; } } /* Main class */ Public Class Main {    /* instance variables */ Stdio.File Infile; Stdio.File Outfile; String[] Args; /* Main method*/ Public Static Int Main( String[] Args ) {        This.Args = Args; Get_files; String Input = Infile.Read; Postfix_interpreter Pfi = Postfix_interpreter; String Output = Pfi.Interpret(Input).To_string; Outfile.Write( Output ); }    /* Get_files method*/ Void Get_files {        Infile = Get_infile( Args ); Outfile = Get_outfile( Args ); Return; }    /* Get_infile method */ Stdio.File Get_infile {        If (Args.Length < 2 Or Args[1] == "--") Return Stdio.Stdin; Else Return Stdio.File( Args[1], "r" ); }    /* Get_outfile method */ Stdio.File Get_outfile {        If (Args.Length < 3 Or Args[2] == "--") Return Stdio.Stdout; Else Return Stdio.File( Args[2], "w' );    } }