The Flair Language Specification


CS 4550
Translation of Programming Languages


Introduction

the logo of the Flair programming language

Flair is a small, mostly functional programming language designed specifically to be used as a manageable source language in a course on compiler design and implementation. It is essentially a subset of Pascal [ 1 | 2 ], an influential imperative language of the 1970s and 1980s. Though small and simple, the language is Turing-complete.

For more on the name Flair and its logo, see the endnotes.



Language Specification

Here are a complete grammar for Flair and a list of syntax features not included in the grammar.

Following the grammar and list of syntax features are informal and possibly incomplete textual descriptions of many of the language's features. The purpose of these sections is to clarify the syntax and semantics of the language. They are not sufficient on their own; they complement the formal definition. If you have any questions, please ask sooner rather than later.



Grammar

Here is the grammar for Flair. In this grammar, ε, the lowercase Greek letter epsilon, stands for the empty string. It indicates that the empty string -- nothing -- is a legal alternative.

            <PROGRAM> ::= program <IDENTIFIER> ( <FORMALS> ) ;
                             <DEFINITIONS>
                             <BODY> .

        <DEFINITIONS> ::= ε
                        | <DEF> <DEFINITIONS>

                <DEF> ::= function <IDENTIFIER> ( <FORMALS> ) : <TYPE>
                             <BODY> ;

            <FORMALS> ::= ε
                        | <NONEMPTYFORMALS>

    <NONEMPTYFORMALS> ::= <FORMAL>
                        | <FORMAL> , <NONEMPTYFORMALS>

             <FORMAL> ::= <IDENTIFIER> : <TYPE>

               <BODY> ::= begin <STATEMENT-LIST> end

     <STATEMENT-LIST> ::= <PRINT-STATEMENT> <STATEMENT-LIST>
                        | return <EXPR>

               <TYPE> ::= integer
                        | boolean

               <EXPR> ::= <EXPR> < <SIMPLE-EXPR>
                        | <EXPR> = <SIMPLE-EXPR>
                        | <SIMPLE-EXPR>

        <SIMPLE-EXPR> ::= <SIMPLE-EXPR> or <TERM>
                        | <SIMPLE-EXPR> + <TERM>
                        | <SIMPLE-EXPR> - <TERM>
                        | <TERM>

               <TERM> ::= <TERM> and <FACTOR>
                        | <TERM> * <FACTOR>
                        | <TERM> / <FACTOR>
                        | <FACTOR>

             <FACTOR> ::= if <EXPR> then <EXPR> else <EXPR>
                        | not <FACTOR>
                        | <IDENTIFIER> ( <ACTUALS> )
                        | <IDENTIFIER>
                        | <LITERAL>
                        | - <FACTOR>
                        | ( <EXPR> )

            <ACTUALS> ::= ε
                        | <NONEMPTYACTUALS>

    <NONEMPTYACTUALS> ::= <EXPR>
                        | <EXPR> , <NONEMPTYACTUALS>

            <LITERAL> ::= <NUMBER>
                        | <BOOLEAN>

    <PRINT-STATEMENT> ::= print ( <EXPR> ) ;

Note: The whitespace in the grammar is intended to aid readability. It is not significant.



Syntax Features

These are the reserved words and symbols of Flair:


    integer   boolean   true     false
    +         -         *        /
    <         =         (        )
    if        then      else
    not       or        and
    print     ,         {        }
    program   function  return   :
    begin     end       ;        .

Integers must be in the range -231 to 231-1.

Identifiers must be no longer than 256 characters.

Flair identifiers are case-sensitive; upper- and lower-case letters are not considered equivalent.

print is a primitive identifier.

A comment begins with a left curly brace, { and continues until the next right curly brace, }. Any characters in a comment are ignored.

Flair operators and punctuation are self-delimiting.

A function may have zero or more formal parameters. The scope of a formal parameter is the body of the function. Arguments are passed by value.

Binary operators and function calls evaluate their arguments from left to right.

Whitespace consists only of blanks, tabs, and end-of-line characters. It serves to separate tokens. Whitespace characters may not appear inside a literal, identifier, keyword, or operator. Otherwise, whitespace is insignificant.

A Flair source file contains a single program.



Data

All data in Flair are integers or booleans, and nearly every element in a program is an expression that produces an integer result or a boolean result.



Atomic Expressions

There are only two boolean values. The two primitive boolean literals are true and false.

Integer literals are strings of digits. There are no leading plus or minus signs to indicate positive or negative values; all integer literals are positive. Leading zeros are not permitted for non-zero integer literals.

User-defined identifiers are strings beginning with a letter and consisting of letters, digits, and the underscore ( _ ).



Compound Expressions

The language provides the following kinds of expression.

Arithmetic

The binary operators add, subtract, multiply or divide two integers.

     x + y
     x - y
     x * y
     x / y

The unary - operator negates an integer.

Comparison

Compares two integers, yielding one of the boolean values true or false. < yields true if its left operand is less than its right operand, and false otherwise. = yields true if its left operand has the same value as its right operand, and false otherwise.

     x < y
     x = y

Boolean Connective

Negates a single boolean value, or computes a combination of two booleans. The unary not yields true if its operand is false, and false otherwise. or yields true if either its left operand or its right operand yields true, and false otherwise. and yields true if both its left operand and its right operand yield true, and false otherwise.

     not x
     x or y
     x and y

or and and short-circuit evaluation when possible.

Conditional Selection

Evaluates a test expression, and uses its value to select one of two other expressions to evaluate. Yields the value of the first of these expressions if the test expression produces a true value, and the value of the second if the test expression yields a false value. The else clause is required.

For example:

     if flag < 0 then
        x + y
     else
        x - y

produces the sum of x and y if flag is less than 0; otherwise, it produces their difference.

Function Call

Applies a function to zero or more arguments, and yields the result. All functions return either an integer result or a boolean value; Flair has no notion of a "void" function.

For example:

     f( x+y, 1 )
computes the sum of x and y, passes that value and a 1 to the function f, and produces the value returned by applying the function to its arguments.

Miscellaneous

Compound expressions can be nested to any depth.

Note that the only user-defined identifiers in Flair are the names of functions and the names of formal parameters to functions. There are no "variables".



User-Defined Functions

Each function declaration consists of the function's name, its formal parameters and their types, the type of the function, and the function's body.

Function names are unique.

A Flair function may refer only to its formal parameters and to other functions.

A Flair function may call itself.



Primitive Functions

For the purposes of user interaction, Flair provides the primitive function print(expression). For example:

     print( x+y )

print writes its argument on standard output, followed by a new line character.

Unlike all user-defined functions, the value of a call to print is undefined. For this reason, if a function contains a call to print, that call must come at the top of the function body.



Programs

A Flair program consists of zero or more function definitions followed by the program's body. The body of the program is called in the same manner as a function.

Users can provide arguments to the main program on the command line. The result returned by the body of the program is printed on standard output.

For example, here is a complete Flair program that prints its argument and returns the absolute value of its argument:

     program absolute( x : integer );
        function abs( n : integer ) : integer
           begin
              return if n < 0
                        then -n
                        else n
           end;
     begin
        print(x);
        return abs(x)
     end.

If this program were compiled into an executable file named abs, then running it under Unix might look something like this:

    mac os x > abs -3
    -3
    3



Endnotes

The Language's Name

I arrived at the name "Flair" by walking a few steps from my original source:

Naming things can be fun.

Note: The Flair programming language defined here is not related in anyway to Flare, an "annotative" programming language, created in an effort to make our programming languages "move closer to the way the human mind works". The words are simply homonyms.

The Language's Logo

The Flair logo, a ball of pulsing blue light, echos the synonym "flare". It appears on the web in a number of places, including this blog post, but I have been unable to find the original source. If you know the original source, please let me know!



Eugene Wallingford ..... wallingf@cs.uni.edu ..... October 28, 2018