Showing posts with label snobol. Show all posts
Showing posts with label snobol. Show all posts

Sunday, June 1, 2008

Creating a simple AIR/Flex UI for a Snobol program

This post presents a little experiment for communicating an Snobol program with an AIR/Flex interface using HTTP.

This post is inspired by the Put a Flex UI On Your Application article by Bruce Eckel.

The example

The example that will be presented is a simple form showing sudo attempts recorded in the /var/log/auth.log log in a Linux box.

A simple program written in Snobol4 using CSnobol4 is used to extract the entries from auth.log . A AIR/Flex program is used to display the data. Both programs are communicated using HTTP.

Although there are several ways to communicate a AIR application with a server side element, HTTP was chosen because of its simplicity to implement in Snobol.

Simple HTTP in Snobol

A way to answer simple HTTP GET method requests from Snobol was required. This requires the creation of a server socket to answer requests. Luckly CSnobol4 includes a nice example for creating a server socket (snolib/serv.sno) using the SERV_LISTEN function. Having this element it was very simple to implement the GET method support.


serverPort = 8080
...
SLOOP FD = SERV_LISTEN("inet", "stream", serverPort) :F(LERR)

INPUT(.NET, 9, "UWT", "/dev/fd/" FD) :F(IERR)
OUTPUT(.NET, 9)

OUTPUT = "Accepting request "

LINE = NET

LINE "GET " GetStringPat $ getString " HTTP/" NUMBER "." NUMBER :F(LERR)

getString ARB "username=" ARB $ requestedUserName ("&" | RPOS(0))

OUTPUT = "Requesting SUDOS for user: " requestedUserName

INPUT(.LOGFILE,10,,"/var/log/auth.log")

NET = "HTTP/1.1 200 OK" CRLF
NET = "Server: SNOBOL4/1.1 (Linux)" CRLF
NET = "Content-Type: text/xml" CRLF
NET = CRLF


Extracting the data

The data extraction process is presented in the following code.


LetterU = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
LetterL = "abcdefghijklmnopqrstuvwxyz"
Digit = "0123456789"
DirectorySeparator = "/"
GetQuerySeparator = "?"
EscapeChar = "%.&="

GetStringChar = LetterU LetterL Digit DirectorySeparator EscapeChar GetQuerySeparator

GetStringPat = SPAN(GetStringChar)

...



NET = "<sudosdata>"

&ANCHOR = 1
LETTER = LetterU LetterL
USERNAMECHAR = Digit LetterU LetterL
USERNAMEPAT = SPAN(USERNAMECHAR)


READLINE LINE = LOGFILE :F(DONE)
LINE SPAN(LETTER) $ month SPAN(" ") SPAN(Digit) $ day ARB " sudo: " USERNAMEPAT . USER :F(READLINE)
LINE ARB "COMMAND=" ARB . COMMAND RPOS(0)

USER requestedUserName :F(READLINE)

NET = "<sudo><date>" month " " day "</date><user>" USER "</user><command>" COMMAND "</command></sudo>" :(READLINE)

DONE

NET = "</sudosdata>" :S(END)


The answer is formated as XML.

The Interface Code

The interface is a very simple program containing a text input to filter the query for a specify user. The useful HTTPService component is used to get the data from the Snobol program.

The Flex part of the program is the following:


<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
title="Sudos Test">
<mx:Script>
<![CDATA[
import flash.utils.Dictionary;
private function callQuery():void {
request.send();
}
]]>
</mx:Script>
<mx:HBox>
<mx:Label text="Sudos" />
<mx:TextInput id="userName" />
</mx:HBox>
<mx:Button label="Query!" click="callQuery()"/>
<mx:DataGrid id="data" dataProvider="{request.lastResult.sudosdata.sudo}">
<mx:columns>
<mx:DataGridColumn headerText="date" dataField="date"/>
<mx:DataGridColumn headerText="user" dataField="user"/>
<mx:DataGridColumn headerText="command" dataField="command"/>
</mx:columns>
</mx:DataGrid>

<mx:HTTPService id="request" url="http://localhost:8080"
useProxy="false"
method="GET">
<mx:request xmlns="">
<username>{userName.text}</username>
</mx:request>
</mx:HTTPService>
</mx:WindowedApplication>


How it looks

An example of running these programs is the following:



Code for this post can be found here.

Tuesday, May 20, 2008

Processing Xml in Snobol4

In this post a quick way to process XML files using a SAX-like method in SNOBOL4 is presented.

I couldn't find a tool for XML parsing/processing for SNOBOL4 so I decided to try to create one to learn more about the language. I decided to use SAX method because is simpler to implement and lets me focus in the text processing part of the code .

Since SNOBOL4 works consumes the input line by line, a function to flatten all the input was created. This helps by eliminating the problem of considering line breaks, but it also makes the code very inefficient since it creates a big line with all the code in in the XML file.


Define('ReadAll()content,tcontent') :(RA_END)
ReadAll
content = ''
RA_LOOP
tcontent = INPUT : F(ERA_LOOP)
content = content tcontent : (RA_LOOP)
ERA_LOOP
ReadAll = content :(RETURN)
RA_END



Having this problem solved, the Xml processing function looks as follows:


Define('ReadXml(inputStr,iPos,fTStart,fTEnd,fText)iPos,fPos,name,closing,attsString,text') :(RX_END)
ReadXml
&anchor = 0
Init
XmlDirectiveL
inputStr POS(iPos) '<?' ARB '?>' @fPos :F(TagStartL)
iPos = fPos :(Init)

TagStartL
inputStr POS(iPos) '<' SPAN(TagChar) $ name ARB $ attsString ('/>' | '>') $ closing @fPos :F(EndTagL)
attsTable = ReadAttributes(attsString)
iPos = fPos
APPLY(fTStart,name,attsTable) :(Init)

EndTagL
inputStr POS(iPos) '</' SPAN(TagChar) $ name '>' @fPos :F(BlanksL)
iPos = fPos
APPLY(fTEnd,name) :(Init)

BlanksL
inputStr POS(iPos) SPAN(Blank) @fPos :F(TextL)
iPos = fPos :(Init)
TextL
inputStr POS(iPos) BREAK('<') $ text @fPos :F(RXXS_END)
iPos = fPos
APPLY(fText,text) :(Init)

RXXS_END

:(RETURN)
RX_END


This code keeps track of the position in the string where the last XML element structure matched by using the iPos variable. The '@' symbol followed by a variable records the position in the input string at a given moment.

Each part of this function marked by the labels XmlDirectiveL, TagStartL, EndTagL, BlanksL, TextL matches one XML element and calls a callback function specified by the fTStart, fTEnd and fText parameters. The call is made by using the APPLY function.

The contents of the ReadAttributes function is the following.


TagChar = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:-'
AttNameChar = TagChar
Blank = " "

Define("ReadAttributes(text)result,attsText,iPOS,fPOS,name,value") :(ratts)
ReadAttributes
result = table()
attsText = trim(text)
iPOS = 0
ratts_loop
attsText POS(iPOS) ARBNO(' ') SPAN(AttNameChar) $ name ARBNO(' ') '=' ARBNO(' ') '"' BREAK('"') $ value '"' @fPOS :F(ratts_loop_end)
result = value
iPOS = fPOS :(ratts_loop)
ratts_loop_end
ReadAttributes = result :(Return)
ratts



An example of the use of these functions is the following:


-include "xmlp.sno"

Define('MyTSFunc(name,attributesTable)') :(MTS_END)
MyTSFunc
OUTPUT = "Into " name
OUTPUT = "id=" attributesTable["id"] :(RETURN)
MTS_END

Define('MyTEFunc(name)') :(MTE_END)
MyTEFunc
OUTPUT = "Out of " name :(RETURN)
MTE_END

Define('MyTTFunc(text)') :(MTT_END)
MyTTFunc
OUTPUT = "Text: " text :(RETURN)
MTT_END

OUTPUT = "XML Test"
Txt = ReadAll()
ReadXml(Txt,0,.MyTSFunc,.MyTEFunc,.MyTTFunc)
END



Given the following input:

<uno>
<dos id="3">
asdf
<tres id="4">
h hh
</tres>
<cuatro>
iasdl
</cuatro>
<cinco id="42"/>
</dos>
</uno>


The program generates:



XML Test
Into uno
id=
Into dos
id=3
Text: asdf
Into tres
id=4
Text: h hh
Out of tres
Into cuatro
id=
Text: iasdl
Out of cuatro
Into cinco
id=42
Out of dos
Out of uno


The benefit of using a SAX-like approach is that the code could be reused for other programs. For example the following program prints all the links and the titles from an OPML file from Google Reader.


-include "xmlp.sno"


Define('TagVisitHandler(name,attributesTable)theUrl,title') :(TVH_END)
TagVisitHandler
name "outline" :F(Return)
title = attributesTable["text"]
theUrl = attributesTable["htmlUrl"]
ident(theUrl , '') :s(return)
OUTPUT = "Link for " title " : " theUrl :(RETURN)
TVH_END

Define('MiTEFunc(name)') :(MTE_END)
MiTEFunc :(RETURN)
MTE_END

Define('MiTTFunc(text)') :(MTT_END)
MiTTFunc :(RETURN)
MTT_END

Txt = ReadAll()
ReadXml(Txt,0,.TagVisitHandler,.MiTEFunc,.MiTTFunc)
END



Documentation from SNOBOL4.ORG was used as reference.

Sunday, January 13, 2008

More information on SNOBOL

A couple of days ago Mike Radow from the SNOBOL4 user group pointed me to some very good SNOBOL4 resources.

First of all there's a SNOBOL4 Yahoo group where active discussions on SNOBOL4 and related languages take place. Also code samples and links are available from this group.

As mentioned in the previous post, one of the main resource sites is http://www.snobol4.org/ by Phil Budne.

A commercial implementation of a SNOBOL4 compiler called SPITBOL is available from http://www.snobol4.com/ .

I also learn about a SNOBOL4 IDE called TkS*LIDE. This IDE is written in TCL/Tk and it worked out of the box, in my Ubuntu machine. Here's a screenshot:



The Wikipedia SNOBOL entry is also good resource.

Friday, December 28, 2007

A quick look at SNOBOL

This entry is just a brief glimpse at the SNOBOL programming language. From its Wikipedia entry:


SNOBOL (String Oriented Symbolic Language) is a computer programming language developed between 1962 and 1967 at AT&T Bell Laboratories by David J. Farber, Ralph E. Griswold and Ivan P. Polonsky.


SNOBOL is a language for string manipulations. Also from its Wikipedia entry:


... SNOBOL was widely used in the 1970s and 1980s as a text manipulation language ... its popularity has faded as newer languages such as Awk and Perl have made string manipulation by means of regular expressions popular ...



This language caught my attention while listening to the OOPSLA podcast episode on the excellent 50-in-50 talk by Guy Steele and Richard Gabriel.

Given that this a programming language exploration blog, learning more about this language provide an excellent opportunity to know more about the first languages for text manipulation.

The best place to learn about the language is http://www.snobol4.org/ a lot of SNOBOL resources can be found there. One of the best resources is a link to the THE SNOBOL4 PROGRAMMING LANGUAGE (Green Book).

All the examples presented in this post were created using the Macro SNOBOL4 in C implementation.

A "Hello world" program in SNOBOL looks like this:


OUTPUT = 'Hello World'
END


As shown here, the assignment to the special OUTPUT variable outputs the value to the standard output.

The inverse is also true for the INPUT variable. For example the following program asks the name of the user.


OUTPUT = "Your name? "
NAME = INPUT
OUTPUT = "Hello " NAME
END


Flow of control is given by jumps to labels given the successful execution of a statement. For example:


ASK
OUTPUT = "Your name? "
NAME = INPUT :F(DONE)
OUTPUT = "Hello " NAME :(ASK)
DONE
OUTPUT = "Finished"
END


This example asks for a name until the input is closed, that is end of file or Ctrl+D (in Linux). The ASK,DONE and END elements are labels; all of them (except for END) are user specified names. The :F(DONE) modifier means jump to DONE if failed and the :(ASK) modifier means jump to ASK.

The most interesting thing about the language is the string pattern matching capabilities. Here's an small(and very incomplete) example that extracts the parts of a simplified URL string:


LETTER = "abcdefghijklmnopqrstuvwxyz"
LETTERORDOT = "." LETTER
LETTERORSLASH = "/" LETTER

LINE = INPUT
LINE SPAN(LETTER) . PROTO "://" SPAN(LETTERORDOT) . HOST "/" SPAN(LETTERORSLASH) . RES

OUTPUT = PROTO
OUTPUT = HOST
OUTPUT = RES
END



In line 6, the contents of the LINE variable is matched against a pattern. The pattern contains the following elements:


  1. The SPAN(LETTER) . PROTO "://" section says identify a sequence of letters followed by "://" and assign them to the variable called PROTO

  2. The SPAN(LETTERORDOT) . HOST "/" secotion says take a sequence of letters and dots followed by "/" and assign then to the variable called HOST

  3. Finally the last section takes the remaining letters and slash characters and assign them to the RES variable




To show a litte program that uses all the elements presented here, I wanted to create a small example that takes as input the authentication /var/log/auth.log and shows all the uses of sudo and the program that was executed. The desired lines look like this:


Dec 28 08:21:42 glorfindel sudo: lfallas : TTY=pts/3 ; PWD=/home/lfallas ; USER=root ; COMMAND=/bin/bash


This file also contains entries other than sudo usages, so we have to ignore them.

Heres the program:


&ANCHOR = 0
UCASE = "ABCDEFGHIJLKMNOPQRSTUVWXYZ"
LCASE = "abcdefghijlkmnopqrstuvwxyz"
DIGIT = "0123456789"
APATH = SPAN(DIGIT)
USERNAMECHAR = DIGIT LCASE UCASE
USERNAMEPAT = SPAN(USERNAMECHAR)

READLINE LINE = INPUT :F(DONE)
LINE " sudo: " USERNAMEPAT . USER :F(READLINE)
LINE "COMMAND=" ARB . COMMAND RPOS(0)

OUTPUT = USER ":" COMMAND :(READLINE)

DONE

END


Here the &ANCHOR assignment tells SNOBOL that pattern matching is performed at any position of the specified string. The ARB element says any character before the next pattern succeeds and the RPOS(0) element is used to identify the end of line.



For future entries I'm going to show more interesting SNOBOL features.