350 likes | 558 Views
The GG Programming Language. “We give it to you.”. The Authors. Kierstan Bell Documentation and Front-end Elizabeth Mutter Front-end Jake Porway Testing and Front-end Jonah Tower Back-end. Language Overview. Jonah. Why GG?. …it makes things easy!. Sockets I/O Threads.
E N D
The GG Programming Language “We give it to you.”
The Authors • Kierstan Bell • Documentation and Front-end • Elizabeth Mutter • Front-end • Jake Porway • Testing and Front-end • Jonah Tower • Back-end
Language Overview Jonah
…it makes things easy! • Sockets • I/O • Threads
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> /* sklar: need to define socklen_t for cunix; not needed for linux */ /* typedef int socklen_t; */ #define TERM '\n' /*-------------------------------------------------------------------- sysabort() system error occured; reports error and exits program ------------------------------------------------------------------*/ void sysabort ( char *m ) { perror( m ); exit( 1 ); } /* end of sysabort() */ /*-------------------------------------------------------------------- client_sock() creates a socket and then attempts to make a connection to that socket ------------------------------------------------------------------*/ int client_sock ( int port ) { int ss, optval = 1; struct sockaddr_in sin; /* (1) create an endpoint for communication */ if (( ss = socket( PF_INET, SOCK_STREAM, 0 )) == -1) { sysabort( "client/socket" ); } /* (1a) set socket options */ if ( setsockopt( ss, SOL_SOCKET, SO_REUSEADDR, /* basically allows socket to bind */ /*(const char *)&optval, sizeof(optval)) == -1 ) {*/ &optval, sizeof(optval)) == -1 ) { sysabort( "client/setsockopt" ); } memset( &sin, 0, sizeof( sin )); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); sin.sin_port = port; Sockets a Simple Client
/* (2) make a connection to the server socket */ if ( connect( ss,(struct sockaddr *)&sin,(socklen_t)sizeof(sin) ) == -1 ) { printf("foobar\n"); sysabort( "client/connect" ); } /* return the socket descriptor */ return( ss ); } /* end of client_sock() */ /*-------------------------------------------------------------------- echo_client() ------------------------------------------------------------------*/ void echo_client ( int port ) { int sock, olen, nwritten, nread, more; unsigned char i; char ibuf[64], obuf[64], *p; /* create client socket on port... */ printf( "client: port=%d\n",port ); sock = client_sock( port ); /* loop, reading input from client and sending it to server */ more = 1; while ( more ) { printf( "enter message to send (q to quit): " ); p = obuf; p = fgets( p,64,stdin ); p[strlen(p)-1] = '\0'; if ( p[0] == 'q' ) { more = 0; p[0] = TERM; p[1] = '\0'; } else { printf( "client: writing message [%s]\n",p ); i = strlen( p ); } if (( nwritten = write( sock, &i, sizeof( i ) )) == -1 ) { sysabort( "client/write" ); } if (( nwritten = write( sock, p, strlen(p) )) == -1 ) { sysabort( "client/write" ); } if ( more ) { if (( nread = read( sock, &i, sizeof( i ))) < 0 ) { sysabort( "client/read" ); } fprintf( stdout,"client: i=%d\n",i ); fflush( stdout ); if (( nread = read( sock, ibuf, i )) < 0 ) { sysabort( "client/read" ); } ibuf[nread] = '\0'; if ( ibuf[0] == TERM ) { more = 0; } else { fprintf( stdout,"client: read message [%s]\n",ibuf ); fflush( stdout ); } } } /* end while more */ /* close socket connection */ close( sock ); This is Really Simple
…Still going } /* end of echo_client() */ /*-------------------------------------------------------------------- main() ------------------------------------------------------------------*/ int main( int argc, char *argv[] ) { int port; if ( argc < 2 ) { printf( "usage: client.x <port>\n" ); exit( 1 ); } sscanf( argv[1],"%d",&port ); echo_client( port ); return( 0 ); } /* end of main() */
And now in GG void main(string arg1, string arg2){ sockconnect(arg1, stoi(arg2)); while(1){ send(getline()); print(recv()); } }
File I/O (in Java) File f = new File(“foobar.txt”);
File I/O (in Java) File f = new File(“foobar.txt”); FileReader fr = new FileReader(f);
File I/O (in Java) File f = new File(“foobar.txt”); FileReader fr = new FileReader(f); BufferedReader in = new BufferedReader(fr);
File I/O (in Java) File f = new File(“foobar.txt”); FileReader fr = new FileReader(f); BufferedReader in = new BufferedReader(fr); String line = in.readLine();
…but wait! try{ File f = new File(“foobar.txt”); FileReader fr = new FileReader(f); BufferedReader in = new BufferedReader(fr); String line = in.readLine(); } Catch(IOException e){ System.err.println(“Oh no!”); }
Look at our Cool Version file f = “foobar.txt”; string line = fgetline(f);
Syntax and Semantics Kierstan
This is Like C, Baby! • Functional language • NOT Object Oriented • C-like syntax int x; int foo(int i) { int y; y = i + 1; return y; } void main() { int z; x = 10; z = foo(x); }
Data Types • boolean boolean b = true; boolean b = false; • char char a = ‘a’; • file file myFile = “myFile.txt” • int int i = 0; • string string hi = “hi”;
Control Flow • while statement • if while(<boolean>){ statements; } if(<boolean>){ statements; }
Built-in Functions • string fgetline(file f) • void fprint(file f, string option, string line) • int getint() • string getline() • string getlocalhost() • int getTime() • void print(string line) • string recv() • string recv(int port) • void send(file file) • void send(file file, int port) • void send(string line) • void send(string line, int port) • void socketclose() • void socketclose(int port) • int socketcreate() • int socketcreate(int port) • int socketconnect(int port) • int socketconnect(string host, int port) • int stoi(string s)
Threaded Functions threaded void funcA(){ print(“a”); } threaded void funcB(){ print(“b”); }
The Compiler Elizabeth
Lexer/Parser • Both written in ANTLR • Lexer • Parses a GG file into Tokens • Parser • Takes the Lexer’s tokens as input • Checks for syntax errors • Creates a tree
Building the Tree For example - GG assignment statement: a = myFunc();
Walking the Tree • Semantic check AND code generation done in one pass • Uses ANTLR’s tree walker • Walks the dummy nodes • … but java code does most of the work • Semantic: • Hashtables keep track of : • Global variables • Local variables • Function declarations • Keywords • Code: • Prints java code to .java files
Code Generation: Java Files • [name-of-file].java • Runnable java file • [name-of-file]MainMethod.java • Wrapper class that contains the translated GG code • [name-of-function]ThreadedFunction.java • Created for each threaded function
Standard Regression Testing • No surprises here… • Small modules tested against base cases using script • Syntactic tests run with Lexer/Parser • Semantic tests run with Tree Walker • Generated code checks run by hand
Syntactic Error Checking • Checks syntax in Lexer/Parser • Basic syntactic errors introduced into correct reference cases • Resulting trees are compared Base Case void main() { int a = 3; (FUNC_DECL void main (BODY (= a 3))) } Error void main() { int a = 3 “Expected SEMI found CCURLY” }
Semantic Error Checking • Only need to check select semantic errors, since most egregious errors are syntactic • Keep log of test results, check for failure void main() { int a = “Not a string”; } Prints to log file: test1-typecheck-incorrect.gg Result: “Expected type int but got ‘Not a string’”
Code Correctness • Not done with automated checking • No mortal should have to hand-generate the Java base case for a client/server program • Instead, functionality is checked thoroughly, not code
Lessons Learned! • Roles are great, but don’t be afraid to “diversify” • Meetings, meetings, and more meetings! There’s comfort in consistency • Clairvoyance – Who knew ANTLR would be so hard • Ctrl-1-0-0 – Who put this in Emacs?