From fd23ee2443b37e354059fdcb010b771797b291e2 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Wed, 23 Apr 2014 17:06:20 +1000 Subject: [PATCH] TCL mode, async{queue,protocol}, and reset line number The TCL mode allows a begin/end construct and TCL code without the leading '@' characters. Add the function name to the hook code comments that are generated. Reset the line counter to 1 between driver modules for error reporting. --- site_ansto/instrument/util/gen_sct.py | 142 ++++++++++++++++++-------- 1 file changed, 98 insertions(+), 44 deletions(-) diff --git a/site_ansto/instrument/util/gen_sct.py b/site_ansto/instrument/util/gen_sct.py index da9224d8..7b1d9b24 100755 --- a/site_ansto/instrument/util/gen_sct.py +++ b/site_ansto/instrument/util/gen_sct.py @@ -41,6 +41,10 @@ global DriveableFunctionTypes global NumberOfLinesIn global NumberOfLinesOut +states = ( + ('tcl', 'exclusive'), + ) + FunctionTypes = [ 'read_function', 'write_function', @@ -147,6 +151,8 @@ tokens = [ 'TEXT_STRING2', 'EQUALS', 'ID', + 'TCL_BEG', + 'TCL_END', ] + list(reserved.values()) # @@ -158,6 +164,38 @@ t_LBRACE = r'{' t_RBRACE = r'}' t_SLASH = r'/' +def t_TCL_BEG(t): + r'{%%' + if Verbose: + print 'TCL_BEG' + t.lexer.begin('tcl') + return t + +def t_tcl_TCL_END(t): + r'.*%%}' + if Verbose: + print 'TCL_END' + t.lexer.begin('INITIAL') + return t + +t_tcl_ignore = "" + +def t_tcl_CODE_STRING(t): + r'.+' + if t.value[0] == '@': + t.value = t.value[1:] + if Verbose: + print 'TCL:', t.value + return t + +def t_tcl_newline(t): + r'\n+' + t.lexer.lineno += t.value.count("\n") + +def t_tcl_error(t): + print("Illegal tcl character '%s'" % t.value[0]) + t.lexer.skip(1) + def t_TEXT_STRING1(t): r'\'[^\']+\'' t.value = t.value[1:-1] @@ -462,6 +500,7 @@ def p_true_false(p): def p_code(p): ''' code : CODE code_type id_or_str EQUALS LBRACE code_block RBRACE + | CODE code_type id_or_str EQUALS TCL_BEG code_block TCL_END ''' p[0] = { 'Code' : { 'name' : p[3], 'type' : p[2], 'text' : p[6] }} @@ -817,15 +856,15 @@ def put_write_function(MyDriver, func): txt += [' set par [sct target]'] txt += [' set cmd "${cmd_str}${par}"'] if func in MyDriver['Funcs'] and len(MyDriver['Funcs'][func]['text']) > 0: - txt += ['# hook code starts'] + txt += ['# %s hook code starts' % func] txt += MyDriver['Funcs'][func]['text'] - txt += ['# hook code ends'] + txt += ['# %s hook code ends' % func] txt += [' if { [hpropexists [sct] geterror] } {'] txt += [' debug_log 1 "[sct] error: [sct geterror]"'] txt += [' error "[sct geterror]"'] txt += [' }'] else: - txt += ['# hook code goes here'] + txt += ['# %s hook code goes here' % func] txt += [' if { [hpropexists [sct] driving] } {'] txt += [' if { [hpropexists [sct] writestatus] && [sct writestatus] == "start" } {'] txt += [' sct driving 1'] @@ -848,11 +887,11 @@ def put_check_function(MyDriver, func): txt += [' set catch_status [ catch {'] txt += [' debug_log 1 "%s tc_root=${tc_root} sct=[sct] resp=[sct result]"' % func] if func in MyDriver['Funcs'] and len(MyDriver['Funcs'][func]['text']) > 0: - txt += ['# hook code starts'] + txt += ['# %s hook code starts' % func] txt += MyDriver['Funcs'][func]['text'] - txt += ['# hook code ends'] + txt += ['# %s hook code ends' % func] else: - txt += ['# hook code goes here'] + txt += ['# %s hook code goes here' % func] txt += [' return "idle"'] txt += [' } catch_message ]'] txt += [' handle_exception ${catch_status} ${catch_message}'] @@ -870,15 +909,15 @@ def put_fetch_function(MyDriver, func): txt += [' }'] txt += [' set cmd "${cmd_str}"'] if func in MyDriver['Funcs'] and len(MyDriver['Funcs'][func]['text']) > 0: - txt += ['# hook code starts'] + txt += ['# %s hook code starts' % func] txt += MyDriver['Funcs'][func]['text'] - txt += ['# hook code ends'] + txt += ['# %s hook code ends' % func] txt += [' if { [hpropexists [sct] geterror] } {'] txt += [' debug_log 1 "[sct] error: [sct geterror]"'] txt += [' error "[sct geterror]"'] txt += [' }'] else: - txt += ['# hook code goes here'] + txt += ['# %s hook code goes here' % func] txt += [' debug_log 1 "%s sct send ${cmd}"' % func] txt += [' if {![string equal -nocase -length 10 ${cmd} "@@NOSEND@@"]} {'] txt += [' sct send "${cmd}"'] @@ -906,15 +945,15 @@ def put_read_function(MyDriver, func): txt += [' error "[sct geterror]"'] txt += [' }'] if func in MyDriver['Funcs'] and len(MyDriver['Funcs'][func]['text']) > 0: - txt += ['# hook code starts'] + txt += ['# %s hook code starts' % func] txt += MyDriver['Funcs'][func]['text'] - txt += ['# hook code ends'] + txt += ['# %s hook code ends' % func] txt += [' if { [hpropexists [sct] geterror] } {'] txt += [' debug_log 1 "[sct] error: [sct geterror]"'] txt += [' error "[sct geterror]"'] txt += [' }'] else: - txt += ['# hook code goes here'] + txt += ['# %s hook code goes here' % func] txt += [' if { ${data} != [sct oldval] } {'] txt += [' debug_log 1 "[sct] changed to new:${data}, from old:[sct oldval]"'] txt += [' sct oldval ${data}'] @@ -947,11 +986,11 @@ def put_checkrange_function(MyDriver, func): txt += [' set hilimit [sct target]'] txt += [' }'] if func in MyDriver['Funcs'] and len(MyDriver['Funcs'][func]['text']) > 0: - txt += ['# hook code starts'] + txt += ['# %s hook code starts' % func] txt += MyDriver['Funcs'][func]['text'] - txt += ['# hook code ends'] + txt += ['# %s hook code ends' % func] else: - txt += ['# hook code goes here'] + txt += ['# %s hook code goes here' % func] txt += [' if { ${setpoint} < ${lolimit} || ${setpoint} > ${hilimit} } {'] txt += [' error "setpoint ${setpoint} violates limits (${lolimit}..${hilimit}) on [sct]"'] txt += [' }'] @@ -981,11 +1020,11 @@ def put_checklimits_function(MyDriver, func): txt += [' set hilimit [sct target]'] txt += [' }'] if func in MyDriver['Funcs'] and len(MyDriver['Funcs'][func]['text']) > 0: - txt += ['# hook code starts'] + txt += ['# %s hook code starts' % func] txt += MyDriver['Funcs'][func]['text'] - txt += ['# hook code ends'] + txt += ['# %s hook code ends' % func] else: - txt += ['# hook code goes here'] + txt += ['# %s hook code goes here' % func] txt += [' if { ${setpoint} < ${lolimit} || ${setpoint} > ${hilimit} } {'] txt += [' sct driving 0'] txt += [' error "setpoint ${setpoint} violates limits (${lolimit}..${hilimit}) on [sct]"'] @@ -1002,11 +1041,11 @@ def put_checkstatus_function(MyDriver, func): txt += ['proc %s::%s {tc_root} {' % (MyDriver['namespace'], func)] txt += [' set catch_status [ catch {'] if func in MyDriver['Funcs'] and len(MyDriver['Funcs'][func]['text']) > 0: - txt += ['# hook code starts'] + txt += ['# %s hook code starts' % func] txt += MyDriver['Funcs'][func]['text'] - txt += ['# hook code ends'] + txt += ['# %s hook code ends' % func] else: - txt += ['# hook code goes here'] + txt += ['# %s hook code goes here' % func] txt += [' if {[sct driving]} {'] txt += [' set sp "[sct target]"'] txt += [' set pv "[hval ${tc_root}/[sct driveable]]"'] @@ -1046,11 +1085,11 @@ def put_halt_function(MyDriver, func): txt += [' debug_log 1 "%s tc_root=${tc_root} sct=[sct] driving=[sct driving]"' % func] txt += [' ### TODO hset [sct] [hval [sct]]'] if func in MyDriver['Funcs'] and len(MyDriver['Funcs'][func]['text']) > 0: - txt += ['# hook code starts'] + txt += ['# %s hook code starts' % func] txt += MyDriver['Funcs'][func]['text'] - txt += ['# hook code ends'] + txt += ['# %s hook code ends' % func] else: - txt += ['# hook code goes here'] + txt += ['# %s hook code goes here' % func] txt += [' sct driving 0'] txt += [' return "idle"'] txt += [' } catch_message ]'] @@ -1078,11 +1117,11 @@ def put_pid_function(MyDriver, func): txt += [' set i_value [expr [sct pid_ivalue] * [sct pid_integ]]'] txt += [' set pid [expr ${p_value} + ${i_value} + ${d_value}]'] if func in MyDriver['Funcs'] and len(MyDriver['Funcs'][func]['text']) > 0: - txt += ['# hook code starts'] + txt += ['# %s hook code starts' % func] txt += MyDriver['Funcs'][func]['text'] - txt += ['# hook code ends'] + txt += ['# %s hook code ends' % func] else: - txt += ['# hook code goes here'] + txt += ['# %s hook code goes here' % func] txt += [' sct pid_output ${pid}'] txt += [' } catch_message ]'] txt += [' handle_exception ${catch_status} ${catch_message}'] @@ -1273,12 +1312,13 @@ def put_mk_sct_driver(MyDriver): txt += put_group(MyDriver, MyDriver['Groups'][group]) txt += [' hsetprop ${scobj_hpath} klass %s' % MyDriver['class']] - if 'mkDriver' in MyDriver['Funcs']: - txt += ['# hook code starts'] - txt += MyDriver['Funcs']['mkDriver']['text'] - txt += ['# hook code ends'] + func = 'mkDriver' + if func in MyDriver['Funcs']: + txt += ['# %s hook code starts' % func] + txt += MyDriver['Funcs'][func]['text'] + txt += ['# %s hook code ends' % func] else: - txt += ['# hook code goes here'] + txt += ['# %s hook code goes here' % func] txt += [' } catch_message ]'] txt += [' handle_exception ${catch_status} ${catch_message}'] txt += ['}'] @@ -1351,14 +1391,24 @@ def put_config(MyDriver): txt += [' set IP [dict get $v ip]'] txt += [' set PORT [dict get $v port]'] txt += [' set name [dict get $v name]'] - txt += [' MakeAsyncProtocol ${name}_protocol'] - txt += [' if { [dict exists $v "terminator"] } {'] - txt += [' ${name}_protocol sendterminator "[dict get $v "terminator"]"'] - txt += [' ${name}_protocol replyterminator "[dict get $v "terminator"]"'] - txt += [' }'] - txt += [' MakeAsyncQueue ${name}_queue ${name}_protocol ${IP} ${PORT}'] - txt += [' if { [dict exists $v "timeout"] } {'] - txt += [' ${name}_queue timeout "[dict get $v "timeout"]"'] + txt += [' if { [dict exists $v "asyncqueue"] } {'] + txt += [' set asyncqueue [dict get $v "asyncqueue"]'] + txt += [' } else {'] + txt += [' if { [dict exists $v "asyncprotocol"] } {'] + txt += [' set asyncprotocol [dict get $v "asyncprotocol"]'] + txt += [' } else {'] + txt += [' set asyncprotocol ${name}_protocol'] + txt += [' MakeAsyncProtocol ${asyncprotocol}'] + txt += [' if { [dict exists $v "terminator"] } {'] + txt += [' ${asyncprotocol} sendterminator "[dict get $v "terminator"]"'] + txt += [' ${asyncprotocol} replyterminator "[dict get $v "terminator"]"'] + txt += [' }'] + txt += [' }'] + txt += [' set asyncqueue ${name}_queue'] + txt += [' MakeAsyncQueue ${asyncqueue} ${asyncprotocol} ${IP} ${PORT}'] + txt += [' if { [dict exists $v "timeout"] } {'] + txt += [' ${asyncqueue} timeout "[dict get $v "timeout"]"'] + txt += [' }'] txt += [' }'] if 'make_args' in MyDriver: txt += [' set arg_list [list]'] @@ -1371,10 +1421,10 @@ def put_config(MyDriver): txt += [' }'] txt += [' }'] txt += [' ${ns}::debug_log 1 "arg_list = $arg_list"'] - txt += [' ${ns}::debug_log 1 "add_%s ${name} aqadapter ${name}_queue $arg_list"' % MyDriver['name']] - txt += [' add_%s ${name} "aqadapter" ${name}_queue {*}$arg_list' % MyDriver['name']] + txt += [' ${ns}::debug_log 1 "add_%s ${name} aqadapter ${asyncqueue} $arg_list"' % MyDriver['name']] + txt += [' add_%s ${name} "aqadapter" ${asyncqueue} {*}$arg_list' % MyDriver['name']] else: - txt += [' add_%s ${name} "aqadapter" ${name}_queue' % MyDriver['name']] + txt += [' add_%s ${name} "aqadapter" ${asyncqueue}' % MyDriver['name']] txt += [' }'] txt += [' }'] txt += [' }'] @@ -1477,8 +1527,12 @@ def process_source(source_files): data = fd.read() fd.close() NumberOfLinesIn = data.count('\n') - print 'Consumed file %s with %d lines' % (source_file, NumberOfLinesIn) + start_line = lexer.lineno yaccer.parse(data) + stop_line = lexer.lineno + print 'Consumed file %s with %d lines (%d, %d)' % (source_file, + NumberOfLinesIn, start_line, stop_line - 1) + lexer.lineno = 1 process_drivers(TheDrivers)