243 lines
6.2 KiB
Awk
243 lines
6.2 KiB
Awk
# Proof of concept implementation for using doxygen to document Igor Pro procedures
|
|
# This awk script serves as input filter for Igor procedures and produces a C-ish version of the declarations
|
|
# Tested with Igor Pro 6.34A and doxygen 1.8.7
|
|
#
|
|
# Thomas Braun: 9/2014
|
|
# Version: 0.23
|
|
|
|
# Supported Features:
|
|
# -Functions
|
|
# -Macros
|
|
# -File constants
|
|
# -Menu items are currently ignored
|
|
|
|
# TODO
|
|
# - don't delete the function/macro subType
|
|
|
|
BEGIN{
|
|
# allows to bail out for code found outside of functions/macros
|
|
DO_WARN=0
|
|
IGNORECASE=1
|
|
output=""
|
|
warning=""
|
|
|
|
menuEndCount=0
|
|
}
|
|
|
|
# Remove whitespace at beginning and end of string
|
|
# Return the whitespace in front of the string in the
|
|
# global variable frontSpace to be able
|
|
# to reconstruct the indentation
|
|
function trim(str)
|
|
{
|
|
if(match(str, /^[[:space:]]+/))
|
|
{
|
|
frontSpace = substr(str, 1, RLENGTH)
|
|
str = substr(str, RLENGTH + 1)
|
|
}
|
|
else
|
|
frontSpace = ""
|
|
|
|
gsub(/[[:space:]]+$/,"",str)
|
|
|
|
return str
|
|
}
|
|
|
|
# Split an already trimmed line into words
|
|
# Returns the number of words
|
|
function splitIntoWords(str, a, numEntries)
|
|
{
|
|
return split(str,a,/[[:space:],&*]+/)
|
|
}
|
|
|
|
# Split params into words and prefix each with "__Param__$i"
|
|
# where $i is increased for every parameter
|
|
# Returns the concatenation of all prefixed parameters
|
|
function handleParameter(params, a, i, iOpt, str, entry)
|
|
{
|
|
numParams = splitIntoWords(params, a)
|
|
str=""
|
|
entry=""
|
|
iOpt=numParams
|
|
for(i=1; i <= numParams; i++)
|
|
{
|
|
# convert igor optional parameters to something doxygen understands
|
|
# igor dictates that the optional arguments are the last arguments,
|
|
# meaning no normal argument can follow the optional arguments
|
|
if(gsub(/[\[\]]/,"",a[i]) || i > iOpt)
|
|
{
|
|
iOpt = i
|
|
entry = a[i] " = defaultValue"
|
|
}
|
|
else
|
|
entry = a[i]
|
|
|
|
str = str "__Param__" i " " entry
|
|
if(i < numParams)
|
|
str = str ", "
|
|
}
|
|
return str
|
|
}
|
|
|
|
{
|
|
# split current line into code and comment
|
|
if(match($0,/\/\/.*/))
|
|
{
|
|
code=substr($0,0,RSTART-1)
|
|
comment=substr($0,RSTART,RLENGTH)
|
|
}
|
|
else
|
|
{
|
|
code=$0
|
|
comment=""
|
|
}
|
|
# remove whitespace from front and back
|
|
code=trim(code)
|
|
|
|
# begin of macro definition
|
|
if(!insideFunction && !insideMacro && ( match(code,/^Window/)|| match(code,/^Proc/) || match(code,/^Macro/) ) )
|
|
{
|
|
insideMacro=1
|
|
gsub(/^Window/,"void",code)
|
|
gsub(/^Macro/,"void",code)
|
|
gsub(/^Proc/,"void",code)
|
|
|
|
# add opening bracket, this also throws away any function subType
|
|
gsub(/\).*/,"){",code)
|
|
}
|
|
# end of macro definition
|
|
else if(!insideFunction && insideMacro && ( match(code,/^EndMacro$/) || match(code,/^End$/) ) )
|
|
{
|
|
insideMacro=0
|
|
code = "}"
|
|
}
|
|
# begin of function declaration
|
|
else if(!insideFunction && ( match(code,/[[:space:]]function[\/[[:space:]]/) || match(code,/^function[\/[[:space:]]/) ) )
|
|
{
|
|
insideFunction=1
|
|
# remove whitespace between function and return type flag
|
|
gsub(/function[[:space:]]*\//,"function/",code)
|
|
|
|
# different return types
|
|
gsub(/function /,"variable ",code)
|
|
gsub(/function\/df/,"dfr",code)
|
|
gsub(/function\/wave/,"wave",code)
|
|
gsub(/function\/c/,"complex",code)
|
|
gsub(/function\/s/,"string",code)
|
|
gsub(/function\/t/,"string",code) # deprecated definition of string return type
|
|
gsub(/function\/d/,"variable",code)
|
|
|
|
# add opening bracket, this also throws away any function subType
|
|
gsub(/\).*/,"){",code)
|
|
|
|
# do we have function parameters
|
|
if(match(code,/\(.*[a-z]+.*\)/))
|
|
{
|
|
paramStr = substr(code,RSTART+1,RLENGTH-2)
|
|
|
|
paramStrWithTypes = handleParameter(paramStr, params)
|
|
paramsToHandle = numParams
|
|
# print "paramStr __ " paramStr
|
|
# print "paramStrWithTypes __ " paramStrWithTypes
|
|
# print "paramsToHandle __ " paramsToHandle
|
|
|
|
code = substr(code,0,RSTART) "" paramStrWithTypes "" substr(code,RSTART+RLENGTH-1)
|
|
}
|
|
}
|
|
else if(insideFunction && paramsToHandle > 0)
|
|
{
|
|
numEntries = splitIntoWords(code,entries)
|
|
|
|
# printf("Found %d words in line \"%s\"\n",numEntries,code)
|
|
for(i=2; i <= numEntries; i++)
|
|
for(j=1; j <= numParams; j++)
|
|
{
|
|
variableName = entries[i]
|
|
if( entries[i] == params[j] )
|
|
{
|
|
paramsToHandle--
|
|
# now replace __Param__$i with the real parameter type
|
|
if(entries[1] == "struct")
|
|
paramType = entries[2]
|
|
else
|
|
paramType = tolower(entries[1])
|
|
|
|
# add asterisk for call-by-reference parameters
|
|
if(match(code,/\&/))
|
|
paramType = paramType "*"
|
|
|
|
output = gensub("__Param__" j " ",paramType " ","g",output)
|
|
# printf("Found parameter type %s at index %d\n",paramType,j)
|
|
}
|
|
}
|
|
}
|
|
# end of function declaration
|
|
else if(insideFunction && match(code,/^end$/))
|
|
{
|
|
insideFunction=0
|
|
code = "}"
|
|
}
|
|
|
|
# structure declaration
|
|
if(!insideFunction && !insideMacro && ( match(code,/[[:space:]]structure[[:space:]]/) || match(code,/^structure[[:space:]]/) ) )
|
|
{
|
|
insideStructure=1
|
|
gsub(/structure/,"struct",code)
|
|
code = code "{"
|
|
}
|
|
|
|
if(insideStructure && match(code,/EndStructure/))
|
|
{
|
|
insideStructure=0
|
|
code = "}"
|
|
}
|
|
|
|
# menu definition
|
|
# submenues can be nested in menus. Therefore we have to keep track
|
|
# of the number of expected "End" keywords
|
|
if(!insideFunction && !insideMacro && ( match(code,/\yMenu\y/) || match(code,/\ySubMenu\y/) ))
|
|
{
|
|
menuEndCount++
|
|
insideMenu=1
|
|
}
|
|
|
|
if(insideMenu && match(code,/\yEnd[[:space:]]*/))
|
|
{
|
|
menuEndCount--
|
|
if(menuEndCount == 0)
|
|
{
|
|
insideMenu=0
|
|
code = ""
|
|
}
|
|
}
|
|
|
|
# global constants
|
|
gsub(/\ystrconstant\y/,"const string",code)
|
|
gsub(/\yconstant\y/,"const variable",code)
|
|
# prevent that doxygen sees elseif as a function call
|
|
gsub(/\yelseif\y/,"else if",code)
|
|
|
|
# code outside of function/macro definitions is "translated" into statements
|
|
if(!insideFunction && !insideMacro && !insideMenu && code != "" && substr(code,0,1) != "#")
|
|
{
|
|
if(code != "}" && !insideStructure && DO_WARN)
|
|
warning = warning "\n" "warning " NR ": outside code \"" code "\""
|
|
|
|
code = code ";"
|
|
}
|
|
|
|
if(!insideMenu)
|
|
{
|
|
output = output frontSpace code comment
|
|
}
|
|
|
|
output = output "\n"
|
|
}
|
|
|
|
END{
|
|
print output
|
|
|
|
if(DO_WARN)
|
|
print warning
|
|
}
|