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.)
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 |
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.
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, 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, 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 is myType or 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 is myType -- implementation of myDerivedType endModule myDerivedType |
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> ::= "?" | "#" | "%" | "$" | [ ":" | is <type> ] <typedExpression> ::= if you omit the <typeDesignation>, the symbol obtains the expression type. |
Here are some correctly coded examples:
| x: myType y is 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