version 0.6.0

Data Types

type  mod_parser::t_parser
 Parser. More...
 

Functions/Subroutines

subroutine mod_parser::parser_initialize (parser, filename, keywords)
 Initialize the parser. More...
 
subroutine mod_parser::parser_finalize (parser)
 Finalize the parser. More...
 
subroutine mod_parser::parser_new_scope (parser, tok, kind)
 Start a new scope. More...
 
subroutine mod_parser::parser_pop_scope (parser, tok)
 Remove the scope at the top of the scope stack. More...
 
subroutine mod_parser::parser_reset_scope (parser)
 Reset the parser to the beginning of the scope. More...
 
subroutine mod_parser::parser_get_identifier_type (parser, tok, id_kind)
 Find the type of an identifier. More...
 
logical function mod_parser::parser_is_identifier_defined (parser, tok)
 Check if a given identifier is defined. More...
 
subroutine mod_parser::parser_add_identifier (parser, tok, intgr, dbl, bool, string)
 Add an identifier to the current scope. More...
 
integer function mod_parser::parser_get_integer_identifier (parser, tok)
 Get the value of an integer identifier. More...
 
double precision function mod_parser::parser_get_double_identifier (parser, tok)
 Get the value of a double identifier. More...
 
logical function mod_parser::parser_get_boolean_identifier (parser, tok)
 Get the value of a boolean identifier. More...
 
character(len=:) function, allocatable mod_parser::parser_get_string_identifier (parser, tok)
 Get the value of a string identifier. More...
 
subroutine mod_parser::parser_get (parser, tok)
 Get the next token. More...
 
subroutine mod_parser::parser_peek (parser, tok)
 Get the next token but not consume it. More...
 
subroutine mod_parser::parser_unget (parser, tok)
 Unget a token. More...
 
logical function mod_parser::parser_next_token (parser, kind, peek)
 Check if the next token is of a specific kind. More...
 
logical function mod_parser::parser_next_keyword (parser, keyword_id)
 Check if the next token is a keyword of a specific kind. More...
 
subroutine mod_parser::parser_expect (parser, kind, has_leading_space, message)
 Ensure that the next token is of a specific kind. More...
 
subroutine mod_parser::parser_throw_error (parser, tok, message)
 Display an error message. More...
 

Detailed Description

Brief description

Let us recall the lexer/parser organization with the 3 main units:

                                keyword list
                                      v
        ┌──────────┐            ┌───────────┐          ┏━━━━━━━━━━━━┓
 files  │          │ characters │           │  tokens  ┃            ┃ ───────>
 ─────> │   File   │ ──────────>│   Lexer   │ ───────> ┃   Parser   ┃  tokens / actions
        │          │            │           │          ┃            ┃ <───────
        └──────────┘            └───────────┘          ┗━━━━━━━━━━━━┛
       mod_source_file            mod_lexer             mod_parser
                                                        mod_identifier
                                                        mod_scope

Usage

A complete usage of the parser can be found in the OBJ Wavefront reader code.

Let us consider the source code example of the lexer section with the file example.txt:

# Print a message to screen
print "I love Notus <3";
# Compute the square of 42 an print the result to screen
square 42;

Specifications:

The following code read the source file and execute the instructions.

! Define an enumerator to identify keywords
!enum, bind(c)
! enumerator :: kw_print = 1
! enumerator :: kw_square
!end enum
type(t_parser) :: parser
type(t_keyword_name), dimension(2) :: keywords
type(t_token) :: tok, next_tok
! Create a list of keywords
keywords(kw_print )%name = "print"
keywords(kw_square)%name = "square"
! Initialize the parser with the file name and the keyword list
call parser_initialize(parser, "example.txt", keywords)
do
! Get the next token
call parser%get(tok)
select case(tok%kind)
case(tk_eof)
write(*,'("EOF")')
exit
case(tk_keyword)
select case(tok%keyword_id)
case(kw_print)
! Get the next token
call parser%get(next_tok)
! Throw an error if no string is found after the keyword
if (next_tok%kind /= tk_string) call parser%throw_error(next_tok, "'print' keyword requires a string")
! Ensure the presence of a semicolon
call parser%expect(tk_semicolon)
! Print the message to standard output
write(*,'(a)') next_tok%string_value
case(kw_square)
! Get the next token
call parser%get(next_tok)
! Throw an error if no integer is found after the keyword
if (next_tok%kind /= tk_integer) call parser%throw_error(next_tok, "'square' keyword requires an integer")
! Ensure the presence of a semicolon
call parser%expect(tk_semicolon)
! Print the square of the integer to standard output
write(*,'(g0)') next_tok%integer_value**2
end select
case default
call parser%throw_error("Forbidden token '"//trim(token_id_to_string(tok%kind))//"'")
end select
end do

Expected output:

I love Notus <3
1764
EOF

Function/Subroutine Documentation

◆ parser_add_identifier()

subroutine mod_parser::parser_add_identifier ( class(t_parser parser,
type(t_token tok,
integer, intent(in), optional  intgr,
double precision, intent(in), optional  dbl,
logical, intent(in), optional  bool,
character(len=*), intent(in), optional  string 
)
Parameters
[in,out]parserParser
[in]tokIdentifier token
[in]intgrIf present, the identifier is an integer (id_integer)
[in]dblIf present, the identifier is a double (id_double)
[in]boolIf present, the identifier is a boolean (id_boolean)
[in]stringIf present, the identifier is a string (id_string)

◆ parser_expect()

subroutine mod_parser::parser_expect ( class(t_parser parser,
integer, intent(in)  kind,
logical, intent(in), optional  has_leading_space,
character(len=*), intent(in), optional  message 
)

If the kind of the next token is the same as the one provided, the next token is consumed. Otherwise, a parser error is thrown.

Typical usage to ensure that the next token is a semicolon ';':

call parser%expect(tk_semicolon)
Parameters
[in,out]parserParser
[in]kindrequired kind of the next token
[in]has_leading_spaceoptional argument that check if the token has a leading space
[in]messageoptional message to display the expected token is not found

◆ parser_finalize()

subroutine mod_parser::parser_finalize ( type(t_parser parser)
Parameters
[in,out]parserParser to finalize

◆ parser_get()

subroutine mod_parser::parser_get ( class(t_parser parser,
type(t_token), intent(out)  tok 
)

Act as a wrapper for lexer_read_token.

Throw an error if the lexer encounters an error.

Parameters
[in,out]parserParser
[out]tokToken

◆ parser_get_boolean_identifier()

logical function mod_parser::parser_get_boolean_identifier ( class(t_parser parser,
type(t_token tok 
)

Throw an error when if the identifier is not found.

Parameters
[in,out]parserParser
[in]tokIdentifier token (tokkink == tk_identifier)
Returns
Boolean value of the identifier

◆ parser_get_double_identifier()

double precision function mod_parser::parser_get_double_identifier ( class(t_parser parser,
type(t_token tok 
)

Throw an error when if the identifier is not found.

Parameters
[in,out]parserParser
[in]tokIdentifier token (tokkink == tk_identifier)
Returns
Double value of the identifier

◆ parser_get_identifier_type()

subroutine mod_parser::parser_get_identifier_type ( class(t_parser parser,
type(t_token), intent(in)  tok,
integer, intent(out)  id_kind 
)

Behavior:

  • Find an identifier starting with the current scope.
  • If an identifier is not found on the current scope, search deeper in the scope stack.
  • Throw an error when the identifier is not found.
Parameters
[in,out]parserParser
[in]tokIdentifier token (tokkind == tk_identifier)
[in]id_kindType of identifier (id_integer, id_double, id_boolean, id_string)

◆ parser_get_integer_identifier()

integer function mod_parser::parser_get_integer_identifier ( class(t_parser parser,
type(t_token tok 
)

Throw an error when if the identifier is not found.

Parameters
[in,out]parserParser
[in]tokIdentifier token (tokkink == tk_identifier)
Returns
Integer value of the identifier

◆ parser_get_string_identifier()

character(len=:) function, allocatable mod_parser::parser_get_string_identifier ( class(t_parser parser,
type(t_token tok 
)

Throw an error when if the identifier is not found.

Parameters
[in,out]parserParser
[in]tokIdentifier token (tokkink == tk_identifier)
Returns
String value of the identifier

◆ parser_initialize()

subroutine mod_parser::parser_initialize ( type(t_parser), intent(inout)  parser,
character(len=*), intent(in)  filename,
type(t_keyword_name), dimension(:), intent(in)  keywords 
)

The parser initializes a lexer with filename and keywords.

Parameters
[in,out]parserParser to initialize
[in]filenameSource file name
[in]keywordsList of keywords

◆ parser_is_identifier_defined()

logical function mod_parser::parser_is_identifier_defined ( class(t_parser), intent(inout)  parser,
type(t_token), intent(in)  tok 
)
Parameters
[in,out]parserParser
[in]tokIdentifier token
Returns
Return .true. if the given identifier is defined

◆ parser_new_scope()

subroutine mod_parser::parser_new_scope ( class(t_parser parser,
type(t_token), intent(in)  tok,
integer, intent(in), optional  kind 
)

Start a new scope beginning at the position of the token tok. It is possible to attribute a flag to identify the scope with the kind argument.

Parameters
[in,out]parserParser
[in]tokToken where the scope starts
[in]kindFlag to identify the scope

◆ parser_next_keyword()

logical function mod_parser::parser_next_keyword ( class(t_parser parser,
integer, intent(in)  keyword_id 
)

The function returns false if the next token is not a keyword or the keyword has the wrong id.

Parameters
[in,out]parserParser
[in]keyword_idwished id of the next keyword

◆ parser_next_token()

logical function mod_parser::parser_next_token ( class(t_parser parser,
integer, intent(in)  kind,
logical, intent(in), optional  peek 
)

If the kind of the next token is the same as the one provided, the next token is consumed (unless peek is set to true) and the function returns .true.. Otherwise, the next token is not consumed and the function returns .false..

Act as a wrapper for lexer_next_token.

Parameters
[in,out]parserParser
[in]kindwished kind of the next token
[in]peekpeek token instead of consumming it

◆ parser_peek()

subroutine mod_parser::parser_peek ( class(t_parser parser,
type(t_token), intent(out)  tok 
)

Act as a wrapper for lexer_peek_token.

Parameters
[in,out]parserParser
[out]tokContains the next token

◆ parser_pop_scope()

subroutine mod_parser::parser_pop_scope ( class(t_parser parser,
type(t_token), intent(in)  tok 
)

If an error occurs, a message is thrown with a position determined by the token arguement tok.

Parameters
[in,out]parserParser
[in]tokToken to tell where a potential error occurs.

◆ parser_reset_scope()

subroutine mod_parser::parser_reset_scope ( class(t_parser parser)
Parameters
[in,out]parserParser

◆ parser_throw_error()

subroutine mod_parser::parser_throw_error ( class(t_parser parser,
type(t_token), intent(in)  tok,
character(len=*), intent(in)  message 
)

Throw an error message to the user with the line, the column and the file where the provided token was read.

Parameters
[in,out]parsercurrent parser
[in]toktoken where the error occurs
[in]messageerror message

◆ parser_unget()

subroutine mod_parser::parser_unget ( class(t_parser parser,
type(t_token), intent(in)  tok 
)

Act as a wrapper for lexer_unget_token.

Parameters
[in,out]parserParser
[in]tokToken to unget