# Introduction

Ce didacticiel est destiné aux nouveaux utilisateurs de la Simple Virtual Machine.

Dans ce didacticiel, vous allez utiliser les types et les interruptions provenant d'extensions.

Le temps de lecture de ce didacticiel est estimé à 15 minutes si l'utilisation des instructions extensions a été abordée.

# Mise en place

Pour commencer, créez le canevas de l'application dans le fichier exécutable types_et_interruptions.svm en utilisant ce code :

    #!/usr/bin/env svm
    DESCRIPTION
    Plugin types and interruptions example
    END
    LOG
    DEBUG "Plugin types and interruptions" STYLE "default"
    PLUGIN "svmcom.so"
    PLUGIN "svmreal.so"
    PLUGIN "svmstr.so"
    PROCESS "application"
    	CODE "main" INLINE
    		:debug BREAK
    	END
    END

# Types extension

Les instructions permettent d'étendre les capacités du processeur. Ici, nous allons étendre celles de la mémoire.

## Allocation mémoire

Modifiez le code pour ajouter une allocation mémoire :

    #!/usr/bin/env svm
    DESCRIPTION
    Plugin types and interruptions example
    END
    LOG
    DEBUG "Plugin types and interruptions" STYLE "default"
    PLUGIN "svmcom.so"
    PLUGIN "svmreal.so"
    PLUGIN "svmstr.so"
    PROCESS "application"
    	CODE "main" INLINE
    		:debug BREAK
    		:memory real.number/r, str.pattern/p
    	END
    END

Puis lancez l'application en mode débugueur. La fenêtre mémoire finit par ressembler à :

Plugin types and interruptions
Memory - K main - P application

Address | Type | Value
--- | --- | ---
&0 | real.number |
&1 | str.pattern |

Alias | Pointer
--- | ---
p | &1*1
r | &0*1

Address:
Display
Aliases
P
Focus
Back
Clear

En somme, la même construction qui servait à nommer des instructions extension sert ici à dénommer des types de valeurs pouvant être écrites en mémoire.

## Utilisation

Dans le débugueur, affichez la fenêtre des extensions, et filtrez sur le texte "real." :

Plugin types and interruptions
Plugins

Definitions
TYPE com.device
TYPE real.number
TYPE str.pattern
STRUCT com.file
STRUCT com.tcp
STRUCT com.terminal
SYSTEM WAITING INSTRUCTION com.command com.device . * -> VALUE ?
INSTRUCTION com.equal com.device 2 -> BLN
WAITING INSTRUCTION com.idle ( ( > | < ( PEP | { PEP [ VALUE KEYWORD ] * } ) ? : protocol ) : mode PTR + : device_arrays ) + -> PTR : active_device
INSTRUCTION com.message [ 'STDOUT' 'STDERR' ] ? VALUE +
SYSTEM WAITING INSTRUCTION com.open PEP : device_type . * : parameters -> com.device
WAITING INSTRUCTION com.prompt ( [ 'STDOUT' 'STDERR' ] ? STR ) : prompt ? [ 'STR' 'INT' ] : output_type -> [ STR INT ]
WAITING INSTRUCTION com.read com.device PEP : protocol [ VALUE KEYWORD ] * : parameters -> STR ?
WAITING INSTRUCTION com.write com.device VALUE *
INSTRUCTION real.add ( [ INT real.number ] [ INT real.number ] + | PTR ) -> real.number
INSTRUCTION real.cmp [ INT real.number ] [ < > = <> <= => ] [ INT real.number ] -> BLN
INSTRUCTION real.div [ INT real.number ] [ INT real.number ] -> real.number
INSTRUCTION real.mul ( [ INT real.number ] [ INT real.number ] + | PTR ) -> real.number
INSTRUCTION real.parse STR -> real.number
INSTRUCTION real.print real.number ( INT INT ) ? -> STR
INSTRUCTION real.sub [ INT real.number ] [ INT real.number ] -> real.number
INSTRUCTION str.char INT : ascii_code -> STR
INSTRUCTION str.cmp STR [ < > = <> <= => ] STR -> BLN
INSTRUCTION str.find STR [ STR str.pattern ] : pattern MUTABLE INT : position MUTABLE INT : size ? -> BLN
INSTRUCTION str.index STR INT : index -> INT : ascii_code
INSTRUCTION str.join ( PTR : array_of_strings | STR + | STR : separator { ( PTR : array_of_strings | STR + ) } ) -> STR
INSTRUCTION str.pattern STR : pattern -> str.pattern
INSTRUCTION str.regex STR [ STR str.pattern ] : pattern -> PTR
INSTRUCTION str.replace MUTABLE STR [ INT 'ALL' ] : occurence [ STR str.pattern ] : pattern_old => STR : new
INSTRUCTION str.size STR -> INT
INSTRUCTION str.split STR [ STR str.pattern ] : separator_pattern -> PTR
INSTRUCTION str.sub STR INT : offset INT : size 'END' : origin_at_end ? -> STR
FUNCTION com.device STRUCT -> com.device ?
FUNCTION com.device_file_close $com.file -> BLN
FUNCTION com.device_file_command $com.file . * -> VALUE ?
FUNCTION com.device_file_open [ < > <> >> ] STR [ 'EXEC' 'PRIV' ] * -> $com.file
FUNCTION com.device_file_print $com.file -> STR
FUNCTION com.device_file_read $com.file -> STR ?
FUNCTION com.device_file_write $com.file STR
FUNCTION com.device_tcp_close $com.tcp -> BLN
FUNCTION com.device_tcp_command $com.tcp . * -> VALUE ?
FUNCTION com.device_tcp_idle $com.tcp MUTABLE INT MUTABLE INT MUTABLE INT
FUNCTION com.device_tcp_open [ < > ] STR [ STR INT ] -> $com.tcp
FUNCTION com.device_tcp_print $com.tcp -> STR
FUNCTION com.device_tcp_read $com.tcp -> STR ?
FUNCTION com.device_tcp_write $com.tcp STR
FUNCTION com.device_terminal_close $com.terminal -> BLN
FUNCTION com.device_terminal_command $com.terminal . * -> VALUE ?
FUNCTION com.device_terminal_idle $com.terminal MUTABLE INT MUTABLE INT MUTABLE INT
FUNCTION com.device_terminal_open [ 'STDIN' 'STDOUT' 'STDERR' ] -> $com.terminal
FUNCTION com.device_terminal_print $com.terminal -> STR
FUNCTION com.device_terminal_read $com.terminal -> STR ?
FUNCTION com.device_terminal_write $com.terminal STR
FUNCTION com.protocol_all STR BLN : eof -> INT ?
FUNCTION com.protocol_available STR BLN : eof -> INT ?
FUNCTION com.protocol_line STR BLN : eof STR ? -> INT ?
FUNCTION com.protocol_size STR BLN : eof INT -> INT ?
FUNCTION real.parse STR -> real.number
FUNCTION str.pattern STR : pattern -> str.pattern
INTERRUPTION com.interrupted

in
Filter

Déjà, "real.number" est bien déclaré comme type. De plus, plusieurs instructions déclarent utiliser ce nouveau type en tant qu'argument ou type de retour.

Modifiez le code pour obtenir :

    #!/usr/bin/env svm
    DESCRIPTION
    Plugin types and interruptions example
    END
    LOG
    DEBUG "Plugin types and interruptions" STYLE "default"
    PLUGIN "svmcom.so"
    PLUGIN "svmreal.so"
    PLUGIN "svmstr.so"
    PROCESS "application"
    	CODE "main" INLINE
    		:debug BREAK
    		:memory real.number/r, str.pattern/p, STR/s
    		CONST real.number "3.14159" -> &r
    		:real.mul @&r 2 -> &r
    		:com.message @&r
    		:real.print @&r -> &s
    		:str.replace @&s 1 CONST str.pattern "^[^.]*" => "X"
    		:com.message @&s
    	END
    END

Lancez l'exécution avec le débugueur. La fenêtre de la mémoire doit ressembler à :

Plugin types and interruptions
Memory - K main - P application

Address | Type | Value
--- | --- | ---
&0 | real.number | 6.28318
&1 | str.pattern |
&2 | STR | "X.28318"

Alias | Pointer
--- | ---
p | &1*1
r | &0*1
s | &2*1

Address:
Display
Aliases
P
Focus
Back
Clear

Et le terminal contient bien les deux valeurs calculées :

    ./types_et_interruptions.svm -d 8080
    ### Simple Virtual Machine 1234 : debug | 2023-01-01 00:00:00 GMT ####################################################################################
    Connection from 127.0.0.1:54321. Login: ************************************************************

    6.28318
    X.28318

Comme vous pouvez le constater :

- Les valeurs de type extension sont stockées dans la mémoire comme les autres types.
- Les instructions peuvent manipuler les types extensions comme les autres types.
- Les valeurs constantes de types extension peuvent être écrites dans le code partout où une valeur de type extension est requise :
  - à condition que l'instruction ne demande pas explicitement une valeur modifiable avec le mot-clef `MUTABLE`,
  - lorsque le type extension ne supporte pas l'opération de construction par constante, une erreur est levée à la compilation,
  - notez également que la construction par constante étant appellée qu'une seule fois lors de la compilation du code, il en résulte une optimisation automatique lorsque cette construction est employée : à chaque fois que l'instruction contenant la construction par constante est appelée, la constante n'est pas reconstruite et la valeur produite durant la compilation est directement utilisée.
- Les valeurs de type extension peuvent être transformées en chaine de caractères par n'importe quelle instruction (comme `:com.message`) et le débugueur.

- Les types extensions permettent à la mémoire de stocker des valeurs définies par des utilisateurs avancés.
- L'allocation d'une adresse avec un type extension se fait en spécifiant le type extension comme n'importe quel type interne de la machine virtuelle dans l'instruction `:memory`.
- Les valeurs de type extension peuvent être employées comme les valeurs de types internes dans les instructions.
- Lorsque le type le supporte ces opérations :
  - les valeurs peuvent être copiées,
  - les constantes de type extension peuvent être spécifiées avec `CONST type_extension "representation_texte_valeur"`,
  - les valeurs peuvent être transformées en une représentation texte.

# Interruptions extension

Remplacez le code par :

    #!/usr/bin/env svm
    DESCRIPTION
    Plugin types and interruptions example
    END
    LOG
    DEBUG "Plugin types and interruptions" STYLE "default"
    PLUGIN "svmcom.so"
    PLUGIN "svmreal.so"
    PLUGIN "svmstr.so"
    PROCESS "application"
    	CODE "main" INLINE
    		:debug BREAK
    		:interruption GLOBAL TERMINATE end
    		:memory com.device/d, STR/s
    		:com.open com.terminal STDIN -> &d
    		:com.read @&d com.all -> &s
    		:com.message "<" @&s ">"
    	:label end
    		:shutdown
    	END
    END

Puis lancez une première fois l'application. Tapez plusieurs lignes de texte, puis sur une nouvelle ligne, tapez la combinaison Control-d :

    ./types_et_interruptions.svm
    test
    test
    <test
    test
    >

Tout s'est bien passé. Recommencez, mais cette fois, tapez la combinaison Control-c au lieu de Control-d :

    ./types_et_interruptions.svm
    test
    test
    ^C### Simple Virtual Machine 1234 : PROCESS application | 2023-01-01 00:00:00 GMT ######################################################################
    Kernel interrupted: @(main, line 5) Interruption !com.interrupted not handled: Read interrupted.

    Core dump:
    Kernel:
    State: I, transmit_interruption, interrupted @(main, line 5) Interruption !com.interrupted not handled: Read interrupted.

    Processor:
     State:
       Next instruction: <main:1/5> (Current one: <main:1/4>)
       Current memory  : &0*0
       Allocated memory: &0*2
       Aliases         : d s
       Flags           :
       Cascaded flags  :
       Local interruption handlers:
       Cascaded local interruption handlers:
     Saved states:
     Global interruption handlers:
        TERMINATE => <main:1/6>

    Code at <main:1/4>:
         :debug BREAK       # <0> @(main, line 1)
         :interruption GLOBAL TERMINATE end # <1> @(main, line 2)
         :memory com.device/d , STR/s       # <2> @(main, line 3)
         :com.open com.terminal STDIN -> &d # <3> @(main, line 4) WAITING SYSTEM
    ====== HERE ======
         :com.read @&d com.all -> &s        # <4> @(main, line 5) WAITING
    ==================
         :com.message "<" @&s ">"   # <5> @(main, line 6)
      :label end
         :shutdown  # <6> @(main, line 8)
     Labels:
      end -> <6>
     Symbols:

    Memory:
      &0: com.device Terminal STDIN
      &1: STR
     Aliases:
      d -> &0*1
      s -> &1*1
     Free space:

    ### Simple Virtual Machine 1234 : SYSTEM | 2023-01-01 00:00:00 GMT ###################################################################################
    Process application interrupted: @(main, line 5) Interruption !com.interrupted not handled: Read interrupted.

Cette fois, l'application a été interrompue par une interruption provenant de l'extension "com" : `!com.interrupted`.

Modifiez une nouvelle fois le code, pour ajouter un gestionnaire d'interruption :

    #!/usr/bin/env svm
    DESCRIPTION
    Plugin types and interruptions example
    END
    LOG
    DEBUG "Plugin types and interruptions" STYLE "default"
    PLUGIN "svmcom.so"
    PLUGIN "svmreal.so"
    PLUGIN "svmstr.so"
    PROCESS "application"
    	CODE "main" INLINE
    		:debug BREAK
    		:interruption GLOBAL TERMINATE ignore
    		:interruption !com.interrupted abort
    		:memory com.device/d, STR/s
    		:com.open com.terminal STDIN -> &d
    		:com.read @&d com.all -> &s
    		:com.message "<" @&s ">"
    		:shutdown
    	:label ignore
    		:return
    	:label abort
    		:com.message "Aborted."
    	END
    END

Relancez l'application et utilisez la combinaison Control-c :

    ./types_et_interruptions.svm
    test
    test
    ^CAborted.

Cette fois, l'interruption a été rattrapée comme n'importe quelle interruption interne.

- Les interruptions peuvent aussi être définies dans les extensions.
- Les interruptions extension s'utilisent comme n'importe quelle interruption interne.
- Elles peuvent s'écrire dans le code avec `!nom_interruption`.
- Des gestionnaires d'interruption peuvent être définis pour les interruptions extension.

# Conclusion

Vous venez de voir comment utiliser des valeurs dont le type est défini dans une extension et comment utiliser des interruptions définies dans une extension.

Tout comme les instructions extension, les types extension permettent d'augmenter considérablement les capacités de la machine virtuelle en plaçant en mémoire des valeurs potentiellement complexes.

Les interruptions extension permettent de distinguer des conditions d'erreur spécifiques à des extensions et y apporter le traitement spécial nécessaire grâce aux gestionnaires d'interruption.