As a language, farSlang has as few rules as I could get away with. The flavor of it is, after all, of being a "casual" scripting language. However, I don't believe that that means that it should not be rigorous. I believe in letting the tools help as much as possible: As a programmer, I want to focus on the problem of the application, not the language. For example, there are no rules about statement order, only that symbols be defined within scope before they are used (yes, you do have to define them). Also, all container statement types, such as proc, if, while, loop, etc., guard a list, or block, of statements, rather than only a single statement, and, thus, are always terminated with an "end-word." Thus, the need for braces, as in C or C++, or begin-end blocks, as in Pascal, is reduced or eliminated. This feature is more like Modula, Oberon, or Ada(sorry).
Another important feature is that there is no explicit memory management in farSlang. Every object is created and accessed by reference, without pointers (i.e., the implementation hides the pointers). This is in keeping with the trends we see in other interpreted languages, such as Java.
Like C, farSlang has no ability to communicate with the outside world: it depends upon a library for that. To make this feasible, the farSlang library includes a parser that can extract salient features from a set of C++ interface files to provide information and code for the farSlang compiler and interpreter.
While we are mentioning linking, farSlang links modules at
run-time - the programmer never needs to deal with this. The
compiler records the resources a modules uses as it is compiled
and its dependencies are resolved when the module is loaded. (This
makes linking a recursive process.)
farVIEW supports an XML language, called Forms
in this documentation, which is a subset of Mozilla's XUL.
farVIEW's Forms allows to create complex on-screen forms using a
declarative language in a similar manner as with HTML. Where
JavaScript provides event handling in HTML, farSlang provides
event handling in farVIEW's Forms. The documentation for Forms is,
to a large extent, in the Change Log
on this website, although you should start with the Mozilla link
and the Forms page in this documentation. There are many code
samples for farSlang in the fars folder, and there are
many Forms/XUL samples showing the use of farSlang in the xul
folder.
Well, you'll probably say that the world doesn't need yet another programming language, but, for a number of reasons, as I considered whether to use some other language or to roll my own, I continually returned to the belief that, at least for the time being, the farVIEW project is better served by upgrading the farSlang language from the old DOS farVIEW. The old farSlang is well documented and simple, it has worked well for a number of years within the farVIEW environment, it has no strings attached, and I am not at the mercy of others for what the language is. No committees. It can be adjusted as needed to make it pour into the new farVIEW environment. Nor can anyone design it out from under my application. So, I bit the bullet a couple of Springs ago and upgraded the definition of the language to support, among other things, inter-module calling, runtime compiling and linking, OOP, access to the C run time library, and access to my substantial farVIEW tool libraries. That also involved revamping the compiler and the interpreter, writing a new C++ parser module, an interface module to support load and run by module name, and a few other bells and whistles.
Here is the "Hello World" program in farSlang:
module helloWorld CMessageBox("", "Hello World", FWW_ATCENTER | FW_OK).Run endModule helloWorld |
or, in a more compact, simplified form:
module helloWorld alert("Hello World") endModule helloWorld |
To run helloworld.far, click the farSlang/Run menu item to obtain the Run Module dialog. Enter "helloworld" in the Module Name field. farVIEW will compile and run the module when you click the Ok button. The message box will appear in the center of your screen. Click the Ok-button or press the Enter-key to close the box. farVIEW will take awhile the first time you run a farSlang module because a bunch of files has to be loaded and linked before the first compile. After the first compile, performance is more as what you would expect.
Note that farSlang programs and scripts are maintained in the fars subfolder.
Also note that a complete list of all APIs available to the farSlang coder in the farVIEW library are available via the link in item 6 above.
There are three applications that use the DLL:
You can continue a statement to the next line if the last character on the the line is the backslash character ("\"). You can also continue a statement using a binary operator as in the following example:
x := "this string is " + "continued on the next line" |
(Comma (",") and Dot-connector (".") works to continue a
statement, too.)
farSlang comments are the same as C++, except you use two dashes instead of two slashes, as in the following example:
-- this is a comment |
Note that the --comment extends only to the end of the line. You
can also use curly braces to delimit comments - they span lines -
as in the following example:
{ this is a comment spanning three lines } |
farSlang doesn't currently support conditional compilation, but it
does support an include directive.
--#i include.inc |
will include the file include.inc. The directive must reside wholly on a single line, must start in column one, but you can place any amount of space between the directive and the file name.
farSlang is not a case sensitive language, however, C++ is. The run-time library is a collection of classes and is implemented in C++ so you must be conscious of case when interacting with the libary. In consequence, I recommend that you always practice case sensitivity, even though I don't like it much, myself. Oh well.
BTW: The notation I am using here is not rigourous, I know it
isn't, but I'm dashing this off (buy that?). Besides, there is
example code to help fill in the gaps I have left. (If you see
some, though, bring them to my attention, I'll try to fix them.)
module <moduleName> [
<baseTypeDesignation>] -- implementation of <moduleName> endModule [<moduleName>] |
(The form of a type designation is given later in the section on Types.)
For example, in one of the code samples included later in this note, its module-statement is
module xml endModule xml |
farSlang allows one and only one module statement within a module source file, and the name of the file must be the name of the module with the extension ".FAR." When the compiler emits the object file, it uses the module name with the extension ".FOB." For the example above, the source file name is xml.far and the object file name is xml.fob.
To assist the farSlang programmer, farVIEW deletes all FOB-files for which there is a FAR-file when you start a farVIEW session, and it recompiles them as needed during the session.
When you declare the event handlers in the events list of a farVIEW object, you identify the code to be executed to handle an event using the module name and the proc name of the handler, as in the following example:
LeftButtonUp = commMod.SendFile |
where commMod is the name of the module in the library,
and SendFile is the name of a parameter-less proc
contained in commMod. LeftButtonUp is the
name of the Left-mouse-button-up event.
When you write farSlang code that calls a proc in another module, or in a C++ class in the library, you use the same notation (though the call can pass parameters, of course), as in the following example:
result := myModule.myProc(param1, param2) |
You can write code in a farSlang module in any order that is
convenient for you to solve the problem, as long as you declare
symbols before you use them and as long as the symbols are within
the appropriate scope (as in Pascal). This means that you can mix
declaration statements, such as var-declarations,
con-declarations, glb-declarations, and procs
interspersed with active statements such as assignment statements
any way you want. Unlike C and C++, you can also nest procs, and
you should do that since nested procs are hidden from the outside
world. For you C and C++ programmers, a proc that you write as a
child of another proc is hidden, while a proc written as the child
of the module is exposed and can be called from the outside world.
(You can hide a module proc with a special marking (tilde "~"),
however, which I'll mention when I discuss procs later.) There are
several farSlang modules at the end of this note that you can look
over to get a more visceral sense of the language.
var x: myType |
where myType is the name of your object type module in the
library. You can declare a variable and initialize it at the same
time as in the following example:
var x := myType |
To derive an object type (say, myDerivedType) from an existing
type-module (a module called myType, say), write the following:
module myDerivedType isa myType -- implementation of myDerivedType endModule myDerivedType |
Under certain conditions, you can also change the type of a value
in a farSlang statement
Several problems that crop up in the way C++ implements OOP are
eliminated with this approach. For example, in farSlang, all procs
are virtual, so you don't have to predict the future by
preregistering a proc as virtual as in C++. If you override the
proc in a derived module, it becomes virtual. You can access the
code of an overridden proc using the same nomenclature that you
use to call any proc that is outside of a module, which I
described earlier.
proc ["~"] <procName> [
<returnTypeDesignation> ] [ (
<formalParameterList> ) ] endProc [ <procName>] <formalParameterList> ::= [ <typedSymbol> { "," <typedSymbol> } |
(See Types below for what a typedVariable is.
Use the tilde ("~") to hide the proc if it is a module proc.
The rules for how you pour farSlang code into a proc are the same
as they are for a module; i.e., not much. You can code any
farSlang statement, including other procs, (except for module
statements, of course) inside a proc.
Intrinsic types | simple types defined and supported by the language |
Module types | object types associated with farSlang modules |
Library types | object types associated with the C++ library |
There are four intrinsic types:
Boolean |
|
have values of "true" and "false" |
Integer |
|
is a 32-bit number |
Float |
|
is a double |
String |
|
uses matching quotes, single-quotes, or back-quotes (whatever they are called:- |
We discussed module types (i.e., classes) earlier. Library types
are the object types exported by the C++ library, which serves as
the farSlang run-time library. The compiler and interpreter
interfaces to the library are generated with the Slanger tool
mentioned earlier. farSlang supports module types and library
types in the same way from the programmer's point of view. Memory
management is transparent to the programmer, so there is little to
say to the experienced OOP programmer about how all that works.
Its pretty standard: you don't use the "->" symbol as in C++,
of course, rather, you use the dot-connector. (if you have a
question, you can email me from the front page of this site.)
Symbol types are generally known at compile-time, except for derived types, of course. But the interpreter tracks the type of a variable at run-time and uses that information when resolving virtual proc calls.
You designate the type of a symbol in a var-declaration, glb-declaration, or con-declaration according to the following form:
<typedSymbol> ::=
<symbol> [ <typeDesignation> ] [ ":="
<typedExpression> ] <typeDesignation> ::= "?" | "#" | "%" | "$" | [ ":" | isa <type> ] <typedExpression> ::= if you omit the <typeDesignation>, the symbol obtains the expression type. |
Here are some correctly coded examples:
x: myType y isa mytype s := "this is a string" i# b? := true |
var <typedSymbol> { "," <typedSymbol> } |
Here is a sample variable declaration list using the examples in
the Types section above:
var x: myType, s$, i#, b? := true |
On second thought, here is something I should mention: there is a
distinction in farSlang between declaring a variable and
initializing it, which may not be obvious. Use the ":" typing
operator to declare a variable or global, and use the assignment
operator (":=") to initialize them. Consider the following
examples:
var x: myType var y := myType |
The first example declares the variable x, while the second
example both declares and initializes y. See the difference?
Obvious enough, until you try to find it in a bunch of code.
Ok, that's it. Now on to globals.
glb <typedSymbol> { "," <typedSymbol> } |
Here is the sample variable declaration list converted to a global
declaration list:
glb x: myType, s$, i#, b? := true |
Note that the first four declarations do not change the (existing)
value of the globals they expose, while the fifth exposes b and
sets it to true. if a global already exists when it is exposed in
a module, its value is inherited by the code in the module. If it
does not already exist, it is instantiated and its value is set to
the default for its type. Of course, code in the module can change
the value of a exposed global as it can a variable.
con <typedSymbol> { "," <typedSymbol> } |
Here is a sample:
con myName := "Paul Medlock", myStreeNumber := 1234 |
The compiler doesn't support constant expressions right now. I
have some code with which to do it, so maybe I'll throw it in and
allow that later.
Module statement: The container for other farSlang statements. Only one module statement per file.
module <moduleName> [
<baseTypeDesignation> ] <moduleStatementList> endModule [<moduleName>] |
Proc statement: The container for
other farSlang statements, including other proc statements.
proc ["~"] <procName> [
<returnTypeDesignation> ] [ (
<formalParameterList> ) ] <procStatementList> endProc [ <procName>] where <formalParameterList> ::= [ <typedSymbol> { "," <typedSymbol> } |
Variable declaration statement:
Declares and optionally initializes variables.
var <typedSymbol> { "," <typedSymbol> } |
Global declaration statement:
Declares and optionally initializes globals.
glb <typedSymbol> { "," <typedSymbol> } |
Constant declaration statement:
Declares and initializes constants.
con <typedSymbol> { "," <typedSymbol> } |
Loop statement: Iterates a statement
list without termination. Use the Continue and Exit statement
types to control the loop.
loop <loopStatementList> endLoop |
Continue statement: Unconditionally repeats a loop
statement, or terminates a begin-end block.
continue |
ContinueIf statement: Conditionally repeats a loop
statement, or terminates a begin-end block.
continueIf <booleanExpression> |
Exit statement: Unconditionally
terminates a loop statement, or begin-end block.
exit |
ExitIf statement: Conditionally
terminates a loop statement.
exitIf <booleanExpression> |
While statement: Iterates a
statement list while a condition is true.
while <booleanExpression>
do <whileStatementList> endWhile |
Repeat statement: Iterates a
statement list until a condition is true.
repeat <repeatStatementList> until <booleanExpression> |
If-Elsif-Else statement: Alternates
among a set of guarded statement lists according to expressions.
if <booleanExpression> then
<ifStatementList> { elsif <booleanExpression> then <elsifStatementList> } [ else <elseStatementList> ] endIf |
Assignment statement: Evaluates an
expression and assigns the result to a variable or global
symbol.
<symbol> := <expression> |
ProcCall statement: Calls a proc
that doesn't return a value.
<procName> [ (<actualParameterList> ) ] |
Return statement: Returns control
from a proc, optionally returning a value according to the type of
the proc.
return [ <expression> ] |
Begin-end statement: Used to group
code because you want to. Use the Continue and Exit
statement ty0pes to control the block.
begin <statementList> end |
Statement list:
{ <statement> ";" } |
and begin con continue continueif do elif else end endif endloop endmodule endproc endwhile exit exitif glb if is loop mod module nil not or proc repeat return then until valid var while |
: (colon)
typing operator ; (semicolon) statement terminator ( (left parenthesis) begins an expression ) (right parenthesis) ends an expression { (left brace) begins a comment } (right brace) ends a comment -- begins a single-line comment [ (left bracket] not currently used ] (right bracket) not currently used + (plus) addition/concatenation operator - (minus) subtraction operator * (asterisk) multiplication operator / (slash) division operator = (equal) comparison operator ~ (tilde) proc hiding operator < (less than) comparison operator <= (less than or equal) comparison operator > (greater than) comparison operator >= (greater than or equal) comparison operator , (comma) list item separator . (period) dereferencing operator and mod not is or |
false/no true/yes maxNr = 2147483647 |
You can use a couple of notational methods to invoke a library
function, depending on your mindset and mood. The first method is
the traditional method as in the following example:
var s := "after the fall" s := after(s, "after ") |
or you can annotate the same call as in the following example:
var s := "after the fall" s := s.after("after ") |
which allows a little of the object-oriented flavor to seep into
the more mundane code we have to write. Don't do that with the
Miscellaneous functions, though.
proc string$(?) |
proc abs#(#) proc char$(#) proc dec#(#) proc inc#(#) proc max#(#, #) proc min#(#, #) proc odd?(#) proc random#(#, #) proc string$(#, #) |
proc abs%(%) proc acos%(%) proc asin%(%) proc atan%(%) proc atan2%(%) proc cos%(%) proc cosh%(%) proc exp%(%) proc log%(%) proc power%(%) proc sin%(%) proc sinh%(%) proc sqr%(%) proc sqrt%(%) proc tan%(%) proc tanh%(%) proc ceiling%(%) proc floor%(%) proc string$(%) |
proc after$($, $) proc before$($, $) proc boolean?($) proc copy$($, #, #) proc delete$($, #, #) proc insert$($, $, #) proc integer#($) proc isalnum?($, #) proc isalpha?($, #) proc iscntrl?($, #) proc isdigit?($, #) proc islower?($, #) proc isprint?($, #) proc ispunct?($, #) proc isspace?($, #) proc isupper?($, #) proc length#($) proc locase$($) proc ord#($) proc pack$($) proc pad$($, #, #) proc pos#($, $, #) proc real%($) proc trim$($, #) proc upcase$($) |
proc beep(#) proc catFileName$(%, $, $) proc changeDirectory?($)) proc changeDisk?($) proc currentDirectory$ proc cutExtension$($) proc cutPath$($) proc extension$($) proc fileExists?($) proc format$($,#) proc beep(#) proc GMT$ proc log?($) proc makeDirectory?($) proc path$($) proc removeFile?($) proc renameFile?($, $) proc sleep#(#) proc time$ proc uniqueID$ |
Begin End ExpandingNode NodeExpanded OpenNode CloseNode DoubleClickNode MouseEnter MouseLeave LeftMouseDown LeftMouseUp LeftDoubleClick MiddleMouseDown MiddleMouseUp RightMouseDown RightMouseUp RightDoubleClick LeftDrop RightDrop AddAlias AddChild EditNode EditEvents EditBody KeyDown? Paint? EndMark? Cut/Copy/Paste? Tick? |
This list is not final.
Note: The current release of farVIEW does not have encryption and authentication facilities, as it is an early alpha release and cannot be trusted. |
Note: in the following examples, types beginning with the letter "C" are C++ library classes and are not documented on this web site. You will find a complete list of the library interface in the files farslang.sym and farslang.xml. Warning: there is no natural-language discussion of the interfaces in either of these files.
Another warning: Do not change farslang.sym. It is used
by the compiler to define the libraries.
-----------------------------------------------------------------------
-- -- This module runs on Paul's computer. It opens a session with Dave's -- computer, then sends him a copy of sendTest.far. It is a simple -- example of Remote Procedure Calling (RPC), since it calls a proc -- on Dave's computer (recvTest.recvFromPaul) to receive the file. -- -- To run, click the farSlang/Run menu item to obtain the Run Module -- dialog. Enter "sendTest" in the Module Name field, and "sendToDave" -- in the Proc Name field. farVIEW will compile and run the sendToDave -- proc when you click the Ok button. -- ----------------------------------------------------------------------- module sendTest
--------------------------------------------------------------------
var Dave
:= UniqueID -- Open a session
with Dave -- Load a text file
into a string list -- Send the string
list to Dave -- Check the result
-- Close the session
with Dave endModule sendTest |
-----------------------------------------------------------------------
-- -- This module runs on Dave's computer. It is executed by the sendTest -- module on Paul's computer as specified in the fourth parameter of the -- SendMessage command. It displays a message box, then stores the file -- on Dave's permission, then quits. -- -- For this program to run, Dave must make sure that his farVIEW is -- listening to incoming requests by setting /preferences/comm/listen=yes -- in his preferences file farview.fix before starting farVIEW. (And, of -- course, there must be a network connection between the two -- computers.) -- ----------------------------------------------------------------------- module recvTest
--------------------------------------------------------------------
if
CMessageBox('Receive From Paul', endModule recvTest |
-----------------------------------------------------------------------
-- This farSlang module is a translation of JavaScript code in an -- article written by Markus Bosshard. -- -- The original article can be found at -- http://msdn.Microsoft.com/peerjournal/vc/g121699b.asp -- -- The farSlang code in this sample module assumes that the XML sample -- file contains the following: -- -- <COMPANY> -- <EMPLOYEE> -- <NAME>Markus Bosshard</NAME> -- <DESCR>Software Design Engineer</DESCR> -- </EMPLOYEE> -- </COMPANY> -- ----------------------------------------------------------------------- module xml var doc := CDocument
--------------------------------------------------------------------
-- Read an XML file like this
--------------------------------------------------------------------
var idx := 0
traverseXML(node.ChildNodes, ident + 2) -- Call traverseXML like this
--------------------------------------------------------------------
proc NewTextElement:
CElement(doc: CDocument, tagName$, tagText$) -- Append a NAME and
a DESCRIPTION element -- Append at the end
of the list -- Add two new entries -- and save the document endModule xml |
Copyright 2000-2003, Paul J. Medlock. All Rights Reserved.
Software downloaded from this site is also copyright 1991-2003,
Paul J. Medlock. All Rights Reserved