📄 ael.tex
字号:
\section{Introduction}AEL is a specialized language intended purely fordescribing Asterisk dial plans.The current version was written by Steve Murphy, and is a rewrite ofthe original version.This new version further extends AEL, andprovides more flexible syntax, better error messages, and some missingfunctionality.AEL is really the merger of 4 different 'languages', or syntaxes:\begin{itemize} \item The first and most obvious is the AEL syntax itself. A BNF is provided near the end of this document. \item The second syntax is the Expression Syntax, which is normally handled by Asterisk extension engine, as expressions enclosed in \$[...]. The right hand side of assignments are wrapped in \$[ ... ] by AEL, and so are the if and while expressions, among others. \item The third syntax is the Variable Reference Syntax, the stuff enclosed in \$\{..\} curly braces. It's a bit more involved than just putting a variable name in there. You can include one of dozens of 'functions', and their arguments, and there are even some string manipulation notation in there. \item The last syntax that underlies AEL, and is not used directly in AEL, is the Extension Language Syntax. The extension language is what you see in extensions.conf, and AEL compiles the higher level AEL language into extensions and priorities, and passes them via function calls into Asterisk. Embedded in this language is the Application/AGI commands, of which one application call per step, or priority can be made. You can think of this as a "macro assembler" language, that AEL will compile into.\end{itemize}Any programmer of AEL should be familiar with it's syntax, of course,as well as the Expression syntax, and the Variable syntax.\section{Asterisk in a Nutshell}Asterisk acts as a server. Devices involved in telephony, like DAHDIcards, or Voip phones, all indicate some context that should beactivated in their behalf. See the config file formats for IAX, SIP,dahdi.conf, etc. They all help describe a device, and they allspecify a context to activate when somebody picks up a phone, or acall comes in from the phone company, or a voip phone, etc.\subsection{Contexts}Contexts are a grouping of extensions.Contexts can also include other contexts. Think of it as a sort ofmerge operation at runtime, whereby the included context's extensionsare added to the contexts making the inclusion.\subsection{Extensions and priorities}A Context contains zero or more Extensions. There are severalpredefined extensions. The "s" extension is the "start" extension, andwhen a device activates a context the "s" extension is the one that isgoing to be run. Other extensions are the timeout "t" extension, theinvalid response, or "i" extension, and there's a "fax" extension. Forinstance, a normal call will activate the "s" extension, but anincoming FAX call will come into the "fax" extension, if itexists. (BTW, asterisk can tell it's a fax call by the little "beep"that the calling fax machine emits every so many seconds.).Extensions contain several priorities, which are individualinstructions to perform. Some are as simple as setting a variable to avalue. Others are as complex as initiating the Voicemail application,for instance. Priorities are executed in order.When the 's" extension completes, asterisk waits until the timeout fora response. If the response matches an extension's pattern in thecontext, then control is transferred to that extension. Usually theresponses are tones emitted when a user presses a button on theirphone. For instance, a context associated with a desk phone might nothave any "s" extension. It just plays a dialtone until someone startshitting numbers on the keypad, gather the number, find a matchingextension, and begin executing it. That extension might Dial out overa connected telephone line for the user, and then connect the twolines together.The extensions can also contain "goto" or "jump" commands to skip toextensions in other contexts. Conditionals provide the ability toreact to different stimuli, and there you have it.\subsection{Macros}Think of a macro as a combination of a context with one namelessextension, and a subroutine. It has arguments like a subroutinemight. A macro call can be made within an extension, and theindividual statements there are executed until it ends. At this point,execution returns to the next statement after the macro call. Macroscan call other macros. And they work just like function calls.\subsection{Applications}Application calls, like "Dial()", or "Hangup()", or "Answer()", areavailable for users to use to accomplish the work of thedialplan. There are over 145 of them at the moment this was written,and the list grows as new needs and wants are uncovered. Someapplications do fairly simple things, some provide amazingly complexservices.Hopefully, the above objects will allow you do anything you need to inthe Asterisk environment!\section{Getting Started}The AEL parser (pbx\_ael.so) is completely separate from the modulethat parses extensions.conf (pbx\_config.so). To use AEL, the onlything that has to be done is the module pbx\_ael.so must be loaded byAsterisk. This will be done automatically if using 'autoload=yes' in\path{/etc/asterisk/modules.conf}. When the module is loaded, it will lookfor 'extensions.ael' in \path{/etc/asterisk/}. extensions.conf andextensions.ael can be used in conjunction witheach other if that is what is desired. Some users may want to keepextensions.conf for the features that are configured in the 'general'section of extensions.conf.To reload extensions.ael, the following command can be issued at theCLI: *CLI> ael reload\section{Debugging}Right at this moment, the following commands are available, but donothing:Enable AEL contexts debug *CLI$>$ ael debug contextsEnable AEL macros debug *CLI$>$ ael debug macrosEnable AEL read debug *CLI$>$ ael debug readEnable AEL tokens debug *CLI$>$ ael debug tokensDisable AEL debug messages *CLI$>$ ael no debugIf things are going wrong in your dialplan, you can use the followingfacilities to debug your file:1. The messages log in \path{/var/log/asterisk}. (from the checks done at load time).2. the "show dialplan" command in asterisk3. the standalone executable, "aelparse" built in the utils/ dir in the source.\section{About "aelparse"}You can use the "aelparse" program to check your extensions.aelfile before feeding it to asterisk. Wouldn't it be nice to eliminatemost errors before giving the file to asterisk?aelparse is compiled in the utils directory of the asterisk release.It isn't installed anywhere (yet). You can copy it to your favoritespot in your PATH.aelparse has two optional arguments:\begin{itemize} \item -d \begin{itemize} \item Override the normal location of the config file dir, (usually \path{/etc/asterisk}), and use the current directory instead as the config file dir. Aelparse will then expect to find the file "./extensions.ael" in the current directory, and any included files in the current directory as well. \end{itemize} \item -n \begin{itemize} \item don't show all the function calls to set priorities and contexts within asterisk. It will just show the errors and warnings from the parsing and semantic checking phases. \end{itemize}\end{itemize}\section{General Notes about Syntax}Note that the syntax and style are now a little more free-form. Theopening '{' (curly-braces) do not have to be on the same line as thekeyword that precedes them. Statements can be split across lines, aslong as tokens are not broken by doing so. More than one statement canbe included on a single line. Whatever you think is best!You can just as easily say,\begin{astlisting}\begin{verbatim}if(${x}=1) { NoOp(hello!); goto s,3; } else { NoOp(Goodbye!); goto s,12; }\end{verbatim}\end{astlisting}as you can say:\begin{astlisting}\begin{verbatim}if(${x}=1){ NoOp(hello!); goto s,3;}else{ NoOp(Goodbye!); goto s,12;}\end{verbatim}\end{astlisting}or:\begin{astlisting}\begin{verbatim}if(${x}=1) { NoOp(hello!); goto s,3;} else { NoOp(Goodbye!); goto s,12;}\end{verbatim}\end{astlisting}or:\begin{astlisting}\begin{verbatim}if (${x}=1) { NoOp(hello!); goto s,3;} else { NoOp(Goodbye!); goto s,12;}\end{verbatim}\end{astlisting}\section{Keywords}The AEL keywords are case-sensitive. If an application name and akeyword overlap, there is probably good reason, and you shouldconsider replacing the application call with an AEL statement. If youdo not wish to do so, you can still use the application, by using acapitalized letter somewhere in its name. In the Asterisk extensionlanguage, application names are NOT case-sensitive.The following are keywords in the AEL language:\begin{itemize} \item abstract \item context \item macro \item globals \item ignorepat \item switch \item if \item ifTime \item else \item random \item goto \item jump \item local \item return \item break \item continue \item regexten \item hint \item for \item while \item case \item pattern \item default NOTE: the "default" keyword can be used as a context name, for those who would like to do so. \item catch \item switches \item eswitches \item includes\end{itemize}\section{Procedural Interface and Internals}AEL first parses the extensions.ael file into a memory structure representing the file.The entire file is represented by a tree of "pval" structures linked together.This tree is then handed to the semantic check routine.Then the tree is handed to the compiler.After that, it is freed from memory.A program could be written that could build a tree of pval structures, anda pretty printing function is provided, that would dump the data to a file,or the tree could be handed to the compiler to merge the data into theasterisk dialplan. The modularity of the design offers several opportunitiesfor developers to simplify apps to generate dialplan data.\subsection{AEL version 2 BNF}(hopefully, something close to bnf).First, some basic objects\begin{astlisting}\begin{verbatim}------------------------<word> a lexical token consisting of characters matching this pattern: [-a-zA-Z0-9"_/.\<\>\*\+!$#\[\]][-a-zA-Z0-9"_/.!\*\+\<\>\{\}$#\[\]]*<word3-list> a concatenation of up to 3 <word>s.<collected-word> all characters encountered until the character that follows the <collected-word> in the grammar.-------------------------<file> :== <objects><objects> :== <object> | <objects> <object><object> :== <context> | <macro> | <globals> | ';'<context> :== 'context' <word> '{' <elements> '}' | 'context' <word> '{' '}' | 'context' 'default' '{' <elements> '}' | 'context' 'default' '{' '}' | 'abstract' 'context' <word> '{' <elements> '}' | 'abstract' 'context' <word> '{' '}' | 'abstract' 'context' 'default' '{' <elements> '}' | 'abstract' 'context' 'default' '{' '}'<macro> :== 'macro' <word> '(' <arglist> ')' '{' <macro_statements> '}' | 'macro' <word> '(' <arglist> ')' '{' '}' | 'macro' <word> '(' ')' '{' <macro_statements> '}' | 'macro' <word> '(' ')' '{' '}'<globals> :== 'globals' '{' <global_statements> '}' | 'globals' '{' '}'<global_statements> :== <global_statement> | <global_statements> <global_statement><global_statement> :== <word> '=' <collected-word> ';'<arglist> :== <word> | <arglist> ',' <word><elements> :== <element> | <elements> <element><element> :== <extension> | <includes> | <switches> | <eswitches> | <ignorepat> | <word> '=' <collected-word> ';' | 'local' <word> '=' <collected-word> ';' | ';'<ignorepat> :== 'ignorepat' '=>' <word> ';'<extension> :== <word> '=>' <statement> | 'regexten' <word> '=>' <statement> | 'hint' '(' <word3-list> ')' <word> '=>' <statement> | 'regexten' 'hint' '(' <word3-list> ')' <word> '=>' <statement><statements> :== <statement> | <statements> <statement><if_head> :== 'if' '(' <collected-word> ')'<random_head> :== 'random' '(' <collected-word> ')'<ifTime_head> :== 'ifTime' '(' <word3-list> ':' <word3-list> ':' <word3-list> '|' <word3-list> '|' <word3-list> '|' <word3-list> ')' | 'ifTime' '(' <word> '|' <word3-list> '|' <word3-list> '|' <word3-list> ')'<word3-list> :== <word> | <word> <word> | <word> <word> <word><switch_head> :== 'switch' '(' <collected-word> ')' '{'<statement> :== '{' <statements> '}' | <word> '=' <collected-word> ';' | 'local' <word> '=' <collected-word> ';' | 'goto' <target> ';' | 'jump' <jumptarget> ';' | <word> ':' | 'for' '(' <collected-word> ';' <collected-word> ';' <collected-word> ')' <statement> | 'while' '(' <collected-word> ')' <statement> | <switch_head> '}' | <switch_head> <case_statements> '}' | '&' macro_call ';' | <application_call> ';' | <application_call> '=' <collected-word> ';' | 'break' ';' | 'return' ';' | 'continue' ';' | <random_head> <statement> | <random_head> <statement> 'else' <statement> | <if_head> <statement> | <if_head> <statement> 'else' <statement> | <ifTime_head> <statement> | <ifTime_head> <statement> 'else' <statement> | ';'<target> :== <word>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -