|
|
Informe técnico/Technical Report – Oct . 2010 IT1/2010
Especificación del lenguaje de programación estructurado jC
The jC structured programming language specification
Palabras clave: Programación estructurada, programación modular, lenguajes de programación.
Keywords: Structured programming, modular programming, programming languages.
Resumen: Existen multitud de lenguajes de programación, algunos de ellos incluso dedicados exclusivamente a la educación. Lógicamente, en la búsqueda de un lenguaje de programación para primero de carrera (especialmente en ingenierías que no son informática, y no precisan conocimientos avanzados), se espera que sea un lenguaje de programación sencillo, es decir, homogéneo, y que sirva como un primer y seguro paso para aprender otros lenguajes de programación. También se espera que tenga una sintaxis similar a C, de manera que sea a su vez similar a C, C++, C# y Java, lenguajes reales empleados en la industria, a estudiar probablemente en cursos más avanzados. La sintaxis de un lenguaje pierde buena parte de su importancia a medida que un programador avanza en su aprendizaje, pero es vital en los primeros cursos. Finalmente, existen varios enfoques sobre el paradigma de programación a emplear primero: estructurado u orientado a objetos. Acerca de este particular, el lenguaje de programación estructurado jC está dedicado a programadores principiantes, que necesiten aprender una sintaxis próxima a C, que sirva de transición suave hacia lenguajes de programación orientados a objetos como Java y C#, empleando todas las características de manera homogénea, e incluyendo algunas avanzadas como la programación modular.
Abstract: There is a wide spectrum of programming languages, some of them even designed for programming learning in mind. The natural objective in the search for a suitable programming language for the first course of the Computer Science graduate, and specially for other engineerings which do not need of advanced knowledge, is to find a simple programming language that will serve as a first, correct step for learning other programming languages. This programming language is thus designed to be simple, specially when considering homogeneity, with a C-like syntax which can suppose a very good starting point for learning programming languages actually used in the industry (as well as probably studied in advanced courses), such as C++, C# or Java. A programming language syntax loses its significance as the programmer advances in his or her learning; however, this characteristic means nearly everything in first-course students. Finally, there exist at least two approaches for teaching programming: object-oriented programming from the very beginning vs. structured programming first, and object-oriented programming secondly. In that sense, jC is a structured programming language designed for beginners, in need of a programming language with a C-like syntax that serves as transition for more advanced programming languages, including only a few characteristic features such as modular programming.
Área de Lenguajes y Sistemas Informáticos
Departamento de Informática
Universidad de Vigo
History of revisions
2010-10-13 First version of this document. Techncial Report IT1/2010.
jC programming language and standard library specification.
2010-10-25 First revision of the specification.
Changed the preference of UTF-16 instead of ISO-8859-1 for character set.
Added the foreach version of the for loop
Modified the getDateAsString() standard function ot make it match ISO 8601.
2011-11-10 Second revision of the specification.
Added advanced operators *= and /=.
Added the (forgotten) logical operators && and ||
Stated the nature of advanced operators as assignments.
Added restrictions to the for loop.
Added restrictions to the switch structure.
2012-01-29 Third revision of the specification.
Fixed vector definition options (new int[3] and new int[] {1, 2, 3}).
Compilation flow revisited.
2013-06-05 Fourth revision of the specification.
Current prototype information revised.
Expansion posibilities discussed.
The jC structured programming language specification
Baltasar García Perez-Schofield
Faculty of Computer Science, Edif. Politécnico, s/n. Campus As Lagoas, University of Vigo
It is difficult to find a suitable programming language for the first course of engineering, specially when this course is not for Computer Science graduates. For the latter, the “first object-oriented programming” approach is many times taken, and they are expected to ease the learning curve by the use of special programming environments such as BlueJ1, unveiling the programming language step by step. When the target public for the programming language are engineering graduate students, apart from the Computer Science ones, finding an appropriate programming language is more difficult. Engineering students many times do not need the complexity involved in object-oriented programming, and a simple, procedural programming language is more suitable, as it permits easily implement calculus and simple formulas from the very beginning.
However, there is no such programming language available nowadays. Pascal was discarded long time ago because of being out of the C-like syntax family, as well as taking type safety to a too radical level. The C programming language is more or less simple, but pointer management gets continually in the way (for example, it is needed for even the simplest string management and also for parameter passing by reference). Using C++ is another possibility, though it requires a careful study of the subset of characteristics of the language that are actually going to be employed. For example, it is possible to use parameter passing by reference, instead of pointers. However, even in that case a lot of complexities must be faced, such as the context dependant meaning of operators.
That is why it was chosen to write the specification of yet another programming language. This language is called jC, and it is not actually new in the sense that it uses a revolutionary syntax or libraries. It is indeed expected to be very similar to already existing (of the C-like syntax family) programming languages. The syntax is borrowed from Java (without the use of classes an other object-oriented capabilities, obviously), while the standard library is borrowed from C. This all means that the objective is not create a completely different programming language in respect to the available ones, but a new programming language that makes it easier for beginners to master it in as less time as possible, while still being able to make up their minds for real programming languages used in the industry such as C, or object-oriented programming languages such as C# or Java.
Though a visual integrated environment such as jcv2 is recommended, hiding all this details, a jcc and jc programs must be provided, compiling programs written in the jC programming language and executing them, respectively3.
Program files must have the jc extension, marking them as jC source code. Modules are written by programmers, and their extensions must be jcm, though there is no significant difference at this level when compared to programs, since both are source code. Files with the jcl extension are modules from any library under the lib directory. Its content format is not specified, though in the current prototype it is compiled Java (and therefore they have the jar extension). Please note that only jC programs (i.e., source code with extension jc) can be compiled: the remaining kinds of source code cannot be compiled or executed directly by the programmer.
Figure 1: The compilation flow for the various types of source codes allowed.
The specific tasks of the compile session are not covered by any norm: any compiler/system designer can carry it out in the best way they choose: there are no special requisites to be compliant. The jcb format file is also not specified. In the current prototype, is is just a source code file containing all modules that are needed for the program to execute. In the future this can be a true binary format, following a formal bytecode specification. Indeed, please note that a jcb file must be, in any case, multiplatform.
Execution is carried out inside the integrated environment, jcv, or using the jc program. The entry point for any jC program is a function called main, which must return an integral number which will be used as an execution result code (as discussed in section 3.11). Follows an example of the compilation and execution of the hola.jc program:
$ ./jcc hola.jc
jC
- v0.3 20100907
f: hola.jc...
Ok
$ ./jc hola
Note that the standard input and output do not need to match the ones in the operating system. In the current implementation, a graphical window is always opened.
The jC programming language is a structured programming language. The main piece of work in this language are procedures and functions. The only difference between functions and procedures is that a procedure is syntactically a function returning void (which is the type name for “no type”).
The primitive types are intentionally minimal. They use and adequateness should be obvious in any case.
Type name |
Explanation |
boolean |
It can hold only two values: true or false. These will be reserved words in the language. There is no direct equivalence between these values and any integer value. |
char |
Used to represent characters, which are represented as integral, unsigned numbers. Implementations are required to implement any of the variants of the available Unicode representations (for example, UTF-8 or UTF-16), using even two bytes for characters, if needed. In any case, confusions related to the equivalence between bytes (code points) and real characters should be avoided. For instance, the first prototype implements UTF-16 through sixteen-byte characters. |
int |
Integral numbers (positive, zero, and negatives). Variables of this type must be 32 bits wide at least (matching the word width of the host machine, where possible), and use 2-complement for internal representation. |
double |
Real numbers, stored as explained in the IEEE 754 norm. Variables of this type should be 64 bits wide at least. |
Table 1: Primitive types of the jC programming language.
Of course, there are others containers for data, which are built from the basic primitive types shown above.
Type name |
Explanation |
char[] |
Used to represent text. |
int[] |
Vectors of integral numbers. |
double[] |
Vectors of real numbers. |
Table 2: Types that can be built from the primitive ones.
Primitive vectors are continuous sequences of values in memory. Their size is associated to the vector, but not stored inside it, at least not in an obvious way for the user. Programmers will have to use the standard function size(), defined in std.util, in order to retrieve its number of elements. Each position n in vector v can be directly accessed by using common notation for vectors: v[ n ], in wich [ n ] is implemented as the operator[] with parameter n. The first position of a vector is 0, and the last position for num size is v[ num -1 ]. Note that the type of a vector or matrix is type[] or type[][], etc., without regarding the size of the vector or array.
The operator [] can be composed with itself and therefore be applied over matrixes or vectors. When applied to vectors, then it returns the position given by the parameter n. When applied to a matrix, it returns the vector inside the matrix in position n. Thus, v[0][1] returns the second position of the first vector (i.e., row), of this two-dimensional matrix.
Vectors can be defined in two ways: in the first one, all the elements and size of the vector are known.
int[] v = new int[]{ 1, 2, 3, 4, 5 };
In the second way, initial lengths and content positions can change from one execution to another.
int wide = 10;
int[][] v = new int[50][wide];
v[ 1 ][wide/2] = 55;
In this case, the operator new is used. The type following new must be one of the primitive ones (section 3.1), and match the type of the variable at the left of the assignment operator, or, in general, the type of the variable that is going to be stored into. The size of each dimension must be given inside each level of square brackets (this is not the operator []).
The operator new is not matched with an operator delete or free of any kind. Memory is automatically managed by the system, as discussed in section 4.
Text is represented as vectors of characters; thus, vector of characters can have a special meaning as text, depending whether they are used as arguments for text-sensible functions or not. It is remarkable be noted that there should not be any difference between a vector of characters and text. For example, it must be possible to directly access the character in position n by using standard vector mechanisms, such as text[ n ].
Identifiers are sequences of characters that form a name chosen for a variable or function. Identifiers can have both letters and digits, as well as the underscore character ('_'); they cannot begin with a digit, however. Identifiers are not limited in length.
Literals appear in the source code as values for variable of the primitive types discussed above, as well as for text.
Type name |
Literals |
boolean |
true, false. |
char |
'a' |
int |
-456, 456, +456 |
double |
3.5, -3.5 |
char[] |
“hello, world!” |
Table 3: Example literals that can appear as direct values in source code for the existing types.
Variables can be declared as pertaining to any of the types discussed above. The type is placed preceding the identifier chosen for its name. After the identifier, the assignment operator '=' can appear or not, preceding a literal value or expression.
int x;
char LetterS = 's';
It must be remarked that variables can only be defined inside a function (discussed in section 3.11). This means that global variables are not allowed. In contrast, global constants (discussed in the next section) are not only allowed, but also encouraged.
The syntax for definition of variables accepts one modifier: final. When this modifier is prepended to the definition of a variable, then this variable is not a variable, but a constant, meaning that its value cannot be chamged.
final double PI = 3.141593; // A similar definition can be found in std.math
PI is a mathematical constant. It does not make sense to modify a value that is constant, and hence, when a constant like PI is modified in the program, a compilation error is produced.
PI = 3.1416;
The modifier final can only be used for defining constants, and nothing else. Applying this modifier to a function would result in a syntactic error.
Block comments can be created by using characters /* for opening them, and */ for closing them. There are limitations for their use, though. These comment marks must always appear at the beginning of a line of source code:
/*
This is allowed
*/
x = 5; /* This is not allowed */
It is also possible to use // as one line comment. The use of these comments is not under any norm.
The operators available in the language are discussed below. The first table shows basic operators to be used in typical mathematical expressions. The only exception is operator +, which can also be used in order to concatenate two pieces of text literals.
writeln( “Hello, “ + “World!” );
The second group, advanced, are shortcuts for typical assignments which can be tedious to repeat again and again. Note that, being assignment shortcuts, it is not possible to use this operators inside other expressions. The third group is used in conditional expressions, i.e., expressions that must return true or false.
Operator |
Meaning of simple operators |
+ |
Adding two numeric expressions, resulting in a number with the result: 2 + 5. |
- |
Subtract one numeric expression from another one, resulting in a number with the result: 2 – 5. |
* |
Multiplication of two numeric expressions, resulting in a number with the result: 2 * 5. |
/ |
Dividing two numeric expressions, resulting in a number with the result: 2 / 5 |
[] |
Access operator for vectors: v[ n ]. |
= |
Assignment operator. There is an identifier4 at its left, and a expression at its right. The expression is evaluated, and the result is assigned to identifier. The types of both the variable pertaining to the identifier and the expression must be equal or compatible: int x = 5. |
Follows the specification for the basic flow structures that can be found in any structured programming language.
Instructions are separated with a semicolon ';'. Instructions are grouped in blocks of code, which are grouped in functions, which can form modules or programs. Allowed instructions are variable declarations, variable assignment and calls to procedures. Variable definitions and assignments can be merged.
int MaxNumberOfDays = 31;
proc( MaxNumberOfDays );
num = f( MaxNumberOfDays );
A block is just a sequence of instructions delimited by the { and } special characters.
{
int num;
int MaxNumberOfDays = 31;
proc( MaxNumberOfDays );
num = f( MaxNumberOfDays );
}
Block delimiters can only appear alone in a given source line, with the exception of the open block character {, which can also appear as its last character. Blocks cannot appear on its own; they are only used as part of decision and repetition structures, as discussed below.
Decisions are represented by the reserved word if, followed by a conditional expression in brackets, followed by a block of instructions which will be executed when the condition is evaluated to true. Alternately, two blocks separated by the reserved word else can be provided, which means that the first one will be executed when the expression is evaluated to true, while the second one will be chosen when the expression is evaluated to false.
Figure 1: Conditional flow diagram describing the behaviour of if.
if ( conditional_expression) <block>
if ( conditional_expression) <block1>
else <block2>
For instance:
if ( num > MaxNumberOfDays ) {
num += 10;
} else {
num -= 10;
}
This is equivalent to the behaviour model shown in Figure 1. In other programming languages, it is possible to avoid blocks by using the special case of a single instruction, which does not need delimiters. Please note that this is not possible in jC.
The switch instruction works allowing to choose between various cases:
switch ( expression ) {
case <opc1>:
<instrucc1>
…
<instrucci>
break;
...
case <opcn>:
<instrucc1>
…
<instruccj>
break;
default:
<instrucc1>
…
<instrucck>
}
For example:
switch( x ) {
case 1:
++x;
break;
case 2:
--x;
break;
default:
x = 0;
}
This construction is equivalent to a chain of if constructions:
if ( expr == opc1) {
<instrucc1>
…
<instrucci>
}
else {
if ( expr == opcn ) {
<instrucc1>
…
<instruccj>
}
else {
<instrucc1>
…
<instrucck>
}
}
So the specific example would be:
if ( x == 1 ) {
++x;
}
else {
if ( x == 2 ) {
--x;
}
else {
x = 0;
}
}
The argument (expression or variable) of switch which actually selects the correct case label must be evaluate to one of the primitive types, explicitly excluding vectors. The default section is executed when no other option was entered. All sections must be finished with a break statement, though a given section can be empty.
char[] operator = readln( “Input an operator (+/-): “ );
if ( operator == '-' ) {
y *= -1;
}
switch( operator[ 0 ] ) {
case '-':
break;
case '+':
result = x + y;
break;
}
Iteration possibilities are present by supporting while, do... while and for loops.
while( conditional_expression ) <block>
Figure 2: Modelling the execution flow for while constructions.
For instance:
int i = 10;
while( i > 0 ) {
--i;
}
Do... while loops are very similar to the previous ones:
do <block>
while( conditional_expression );
In both cases, the block is executed continuously until conditional_expression returns false, as shown in Figure 2 for while loops and in Figure 3 for do... while loops.
A similar example could be:
i = 10;
do {
--i;
} while( i > 0 );
Figure 3: Modelling the execution flow for do... while iteration constructions.
The main difference between both of them is that do... while loops assure the execution of the loop at least one time. While loops, however, may never get to execute their blocks.
Following the example from the previous section:
char[] operator;
double x;
...
do {
operator = readln( “Input an operator (+/-): “ );
switch( operator[ 0 ] ) {
case '-':
y *= -1;
writeln( resultado );
About the last kind of iteration construction:
for ( initialization_section; conditional_expression; increment_section) <block>
The initialization section (which an be omitted) can even contain the definition of a variable. The loop is executed until the conditional_expression returns false (this expression cannot be omitted). The increment_section is always executed after each loop iteration (and can be omitted). The specific sequence, and the equivalence to the while loop is the following one:
initialization_section;
while( conditional_expression )
{
<block>
increment_section;
}
int x = 0;
for(int i = 10; i > 0; --i) {
x += 5;
The continue statement means that the next instructions of the body of the loop are ignored for that iteration. The break statement is also allowed, meaning that the loop in which it is contained is abandoned. In the next example, only even elements in the range of [0,5) are visited (note that the for loop is firstly written to run over elements in the range of [0,10):
int x = 0;
for(int i = 0; i < 10; ++i) {
if ( x == 5 ) {
break;
}
if ( ( i % 2 ) != 0 ) {
continue;
}
x += 5;
}
Finally, the existence of the for-each form of the for loop is encouraged, though optional. The semantics of this loop can be explained on top of the regular for loop. This loop is executed for each element in the vector, and only a variable that will be used for each element, and the vector in which it will run are provided.
for ( <variable definition> : <expression returning vector> ) <block>
int[] v = new int[]{ 1, 2, 3, 4, 5 };
for(int
elem : v) {
writeln( elem );
}
Follows the equivalent code block of the example above.
int[] v = new int[]{ 1, 2, 3, 4, 5 };
int elem = 0;for(int i = 0; i < size( v ); ++i) {
elem = v[ i ];Functions are a construction designed to group instructions that are useful for a specific task. For a function, it is needed to specify the return type, the identifier that will name, and a list of formal parameters, if there is one (it is not mandatory), in brackets:
<type> <function_name>( [<parameter_type> <paramater_name>[, …]])
A formal parameter is technically a local variable defined normally with its type and identifier. The only difference is that this local variables will receive their initialization values from outside the function. For example:
int add(int a, int
b)
{
return a + b;
int main()
{
writeln( add( 6, 5 ) );
return ExitSuccess;
When a function is actually a procedure, meaning that it is a function with nothing to return, the return type to specify is void. The return instruction is optional. Also note that the parameter list is optional in any case, and that the brackes can appear empty.
void foo()
{
...
}
Parameter passing can be mainly in two sorts: passing by reference or passing by value. While passing by reference means that the actual variable is passed to the function foo (though the identifier is not needed to coincide), and therefore the modifications carried out in that function are permanent for the variable. When a variable is passed by value, then only the value of the variable is copied in the parameter of the function. This means that without regard of the name of the identifier of the parameter, any change in that parameter during foo will not survive the end of foo.
About parameter passing in jC, it always occurs by reference, excepting the primitive types: int, double and char, which are passed by value. In the following example, vector (of type int[]) vx and x (of type int), are passed as parameters to function f. Both are modified inside it, but that does not mean both modifications impact the caller (main, in this specific case).
import std.util;
import std.io;
void f(int x, int[] v)
{
x = 5; // This
modification will not be reflected in the caller.
v[ 0 ] = 55; // This modification will be
reflected in the caller.
}
int main()
{
int[] vx = new int[]{ 1, 2, 3,
4, 5 };
int x = 6;
f( x, vx );
writeln( x ); // Writes 6
// Writes: 55 2 3 4 5
for(int i = 0; i <
size( vx ); ++i) {
write( vx[ i ] );
write( ' ' );
}
return ExitSuccess;
}
The output of the program will be '6' (this is the contents of x, which is modified in f, but this modification is not reflected in the caller) and '55 2 3 4 5', since the vector is actually modified in f, and this modification is reflected in the caller, since vx (of type int[]) is not primitive.
A special case of function is main. This function is the entry point of a program written in jC, meaning that the execution will always start in the first instruction of main. When the compiler is configured for a beginner, the main() function can be omitted altogether: it will generate a void main() function for the user. The compiler, in expert mode, will support this function using a semi-fixed signature: it does not receive any parameter, and it returns void; or an int with the result of the execution (valid result codes are available in the library std.util, discussed in section 5.6):
int main()
{
…
return ExitSuccess;
}
A module is a construction designed for grouping related functions, i.e., functions which have related tasks. For example, a module could be created for managing complex numbers. Each function would do a different task, but all those tasks would be related to complex numbers management.
A module is similar to a program, though there are indeed actually two differences: there is not a main function (the execution entry point), since a module cannot be executed. Secondly, all functions and constants (lets name it members of the module) in the module need a prepended visibility keyword. Visibility attributes can only classify a member as pertaining to two sets: public members, which can be invoked or used from another module or program, and private ones, which cannot be only invoked or used from the module in which they are defined. This means that private members are of private use of the remaining functions in the module. The set of public members is the interface of the module, with which it will be used from a program or another module.
For example:
// my.jcm: My module
public int sqr(int x)
{
return x * x;
}
This module can be used from a program or another module by using the import keyword. Please note that in the case of user modules there are no prefixes for the names of the modules.
import my;
Visibility keyword |
Specifies |
public |
Can be invoked from another module or program that imports the module in which it is defined. |
private |
Can only be invoked by other functions of its own module. |
Table 4: Visibility keywords available.
jC is a garbage-collected programming language. For example, in the next source code, a text variable is created, converted to a number (type int), and discarded altogether.
int x = strToInt( readln( "Input the first operand: " ) );
The effect of the text variable being discarded is that it can be collected. Collection can happen at the same time a variable is marked as discarded, or later. Real variable elimination from memory can also happen at the same time the variable is collected, or later, as well.
Thus, the implementation of the garbage collection mechanism is not covered by this specification. It can be a simple mark and sweep based algorithm or an advanced stack inspection based one. It is not possible to let this task be accomplished by the programmer, though, The use of a keyword (such as delete) for variable erasing, or any other programmer interference in memory management is simply not allowed.
Follows a discussion of the minimum standard library that should be available for the language. These modules of the standard library must be located in a subdirectory called lib/std. The standard library is designed to be mastered in a couple of weeks, without any previous knowledge. This does not mean that the capabilities of the programming language should be short or minimal, since it must be possible to extend it, as explained in table 5. Note that only the standard library is mandatory in order to create a fully compliant library.
Once a library l is placed under the lib directory and its appropriate subdirectory (called prefix), it should be imported in the program as prefix.l. For example:
import std.io; // The standard input/output library.
import net.http; // An optional library related to http network protocol.
import ext.string; // An optional library extending the possibilities of std.string
Directory |
Libraries to place |
lib/std |
Standard library. |
lib/ext |
Extensions to the standard modules library. |
lib/os |
Operating-system related libraries. |
lib/ui |
User interface related libraries. |
lib/net |
Networking libraries. |
lib/media |
Multimedia libraries. |
lib/opt |
Other libraries. |
Table 5: Placement of libraries. By default, only the lib/std directory needs to exist..
This library just provides constants to manage the maximum and minimum values for integral and real types. It is named std.limits.
Constant |
Explanations |
final int MaxInt |
The maximum integer that can be stored. |
final int MinInt |
The minimum integer that can be stored. |
final double MaxDouble |
The maximum double that can be stored. |
final double MinDouble |
The minimum double that can be stored. |
Table 6: Constants defined in the limits library.
The following functions are defined in the mathematics library, named std.math.
double abs (double x)
Absolute value function.
int abs (int x)
Absolute value function.
double cos (double x)
Cosene function.
double sin (double x)
Sine function.
double acos (double x)
Arc cosene function.
double asin (double x)
Arc sine function.
double tan (double x)
Tangential function.
double atan (double x)
Arc tangential function.
double exp (double x)
Euler's number e raised to the power of x.
double log (double x)
Returns the natural logarithm (base e) of x.
double log10 (double x)
Returns the base 10 logarithm of x.
double floor (double x)
Returns the integer number that is smaller than x.
double ceil (double x)
Returns the integer number that is bigger than x.
double pow (double x, double y)
Returns the a number x to the y-th power.
double sqrt (double x)
Returns the square root.
int round (double x)
Returns the closest integer value.
double random (double x)
Returns a number in the range [0, 1).
double toDegrees (double x)
Returns a conversion of x to degrees.
double toRadians (double x)
Returns the conversion of x to radians.
Constant |
Explanations |
final double PI |
The PI constant, aproximately 3.1416 |
Table 7: Constants defined in the math library.
The input and output offered should be very basic, so only basic console input and output is covered. This module is named std.io. Functions print() and println() should be synonims of write() and writeln(), though this is not mandatory.
void write(char[] s)
Prints a string on console.
void writeln(char[] s)
Prints a string on console, and changes line.
void writeln()
Changes to next line on console.
char[] readln()
Reads a string from console.
char[] readln(char[] msg)
Reads an string from console, accepting a message to be displayed.
The character library manages operations related to characters. It is named as std.charType.
boolean isLetter (char ch)
Decides whether the char is letter.
boolean isDigit (char ch)
Decides whether the char is digit or letter.
boolean isAlphaNumeric (char ch)
Decides whether the char is digit or letter.
boolean isControl (char ch)
Decides whether the char is a control character.
boolean isLowerCase (char ch)
Decides whether the char is lower case.
boolean isUpperCase (char ch)
Decides whether the char is upper case.
boolean isSpace (char ch)
Checks if the character is a delimiter.
boolean isPunctuation (char ch)
Checks if the character is punctuation mark.
char toLowerCase (char ch)
Changes the char to lower case.
char toUpperCase (char ch)
Changes the char to upper case.
Constant |
Explanations |
final String PunctuationChars |
Punctuation characters. |
Table 8: Constants defined in the character library.
This library manages text as character vectors, as it is a standard in jC. This library is named std.string.
int strLen (char[] s)
Returns the size of a string.
char[] strCreate (String s)
creates a new string
char[] strCopy (char[] s)
Copies a new string to an existing string.
char[] strConcat (char[] s1, char[] s2)
Concats a string to an existing string.
int strCompare (char[] s1, char[] s2)
Compares a string to another one (lexicographically).
int strIndexOf (char[] s, char ch)
Returns the position of ch in s.
int strLastIndexOf (char[] s, char ch)
Returns the last position of ch in s.
int strToInt (char[] s)
Converts a string to an int number.
double strToDbl (char[] s)
Converts a string to a double number.
char[] intToStr (int x)
Converts an int number to string.
char[] charToStr (char ch)
Converts a char to string.
char[] strToLowerCase (char[] str)
Converts a str to lower case.
char[] strToUpperCase (char[] str)
Converts a str to upper case.
This library defines functions and constants that are useful for various tasks. It is named std.util, and probably it is mandatory to import it in all programs that do anything useful.
int size (vector)
returns the size of a vector of any type.
boolean isEmpty (vector)
returns whether the size of a vector is zero
void exit (int x)
Terminate the program with a specific error code for the operating system.
void assert (boolean expr, char[] msg)
Tests a condition expr, stopping the program when it is not evaluated to true.
int[] getDate ()
Returns the current date in the system.
char[] getDateAsString ()
Returns the current date in the format "year-month-day" (ISO-8601).
int[] getTime ()
Returns the current time in the system.
char[] getTimeAsString ()
Returns the current time in the format "hour:minute:second".
Constant |
Explanations |
final int ExitSuccess |
The standard return code for a program that terminates correctly. |
final int ExitFailure |
The standard return code for a program that terminates incorrectly. |
Table 9: Constants defined in the utilities library.
No programming language specification can be complete without the Hello, world! example program. The possible variants are as follows:
import std.io;
import std.io;
void main()
{
import
std.io;
import std.util;
int
main()
{
writeln( “Hello, world!” );
}
When no specific code is returned, then 0 is offered as exit code. Indeed, ExitSuccess, defined in util, is always 0.
As discussed in sections 3 and 3.11, the libraries (section 5) io (section 5.3) and util (section 5.6) are imported in order to specifically use the function writeln, and the exit code constant ExitSuccess, respectively. The entry point is function main (as discussed in section 3), and thus this function is defined (it is actually the only needed one in this example). The function writeln is called in order to write a string in the standard output. The main function is then terminated by returning to the operating system the correct exit code for successful completion, defined in util.
The jcv program is an integrated environment specially designed for the jC programming language. This integrated environment is aimed at ease of use, above all other considerations. The integrated environment is able to manage only one file at the same time, and it always obvious how to load, save, and execute programs.
Figure 4: The vjC integrated programming environment.
The current prototype has been written in Java, and it generates a mixing between interpreted code (using Bsh, a Java-based interpreted language) and compiled code for the JVM (Java Virtual Machine).
Specifically, libraries are written as Java classes in which all their members are static. Those member that can be used by the programmer of jC will be marked as public. Follows the implementation of std.limits:
/**
jC limits standard library package
@name Limits (jC Standard Library
@brief Reports on limits of numerical types
@date 2010-12-1
@author jbgarcia@uvigo.es
*/
public class limits {
/// The maximum
integer that can be stored
public static final int MaxInt =
Integer.MAX_VALUE;
/// The minimum
integer that can be stored
public static final int MinInt =
Integer.MIN_VALUE;
/// The maximum
double that can be stored
public static final double MaxDbl =
Double.MAX_VALUE;
/// The minimum
double that can be stored
public static final double MinDbl =
Double.MIN_VALUE;
} // class limits
The current prorotype uses reflection in order to create a skeleton of the class, containing all public members.
When the program is executed, the code in this libraries is compiled, which means that it will perform better than the code written by the programmer in a jC program.
It is also possible to use an existing library from another one. In that case, it can be signaled to the compiler that the former is a prerequisite for the latter, by adding a private constant such as:
private static final String _jc_lib_req = "media.gw";
In case there are more than one library, then they should be separated by semicolons.
The jC programming language has been specified, along with its minimal standard library. This programming language is designed to share many characteristics with other programming languages, and to be able to master it in a short period of time, due to its simplicity and homogeneity. Thus, it is a very good starting platform for learning other programming languages of the C-like syntax family, such as C, Java or C#.
While the programming language syntax and constructions are borrowed from Java and C, the standard library, which can be easily expanded, was borrowed from C. Memory management was borrowed from Java as well, in the sense that it is automatically managed by the system.
This programming language was specially designed for students of other engineerings, apart from the Computer Science one, in mind. This way, it is possible to translate formulas and mathematical calculus easily, even for a beginner.
1Availabe at BlueJ.org.
2jcv is a Visual Integrated Development Environment designed for jC. This program is discussed later.
3The jC programming language can be downloaded from http://webs.uvigo.es/jbgarcia/prys/
4The only exception to this rule appears when assigning to vector or matrixes positions, in which the [] operator must be applied in order to indicate the position of the vector the result of the expression must be stored in.