sgmlparser.tcl

来自「Linux下的MSN聊天程序源码」· TCL 代码 · 共 2,131 行 · 第 1/5 页

TCL
2,131
字号
## Results:#	Markup declarations parsed may cause callback invocationproc sgml::ParseDTD:External {opts dtd} {    variable MarkupDeclExpr    variable MarkupDeclSub    variable declExpr    array set options $opts    upvar #0 $options(parameterentities) PEnts    upvar #0 $options(externalparameterentities) ExtPEnts    upvar #0 $options(-statevariable) state    # As with the internal DTD subset, watch out for    # entities with angle brackets    set mode {} ;# normal    set delimiter {}    set name {}    set param {}    set oldState 0    catch {set oldState $state(inInternalDTD)}    set state(inInternalDTD) 0    # Initialise conditional section stack    if {![info exists state(condSections)]} {	set state(condSections) {}    }    set startCondSectionDepth [llength $state(condSections)]    while {[string length $dtd]} {	set progress 0	set PEref {}	if {![string compare $mode "ignore"]} {	    set progress 1	    if {[regexp {]]>(.*)} $dtd discard dtd]} {		set remainder {}		set mode {} ;# normal		set state(condSections) [lreplace $state(condSections) end end]		continue	    } else {		uplevel #0 $options(-errorcommand) [list missingdelimiter "IGNORE conditional section closing delimiter not found"]	    }	} elseif {[regexp ^(.*?)%($::sgml::Name)\;(.*)\$ $dtd discard data PEref remainder]} {	    set progress 1	} else {	    set data $dtd	    set dtd {}	    set remainder {}	}	# Tokenize the DTD (so far)	# Protect Tcl special characters	regsub -all {([{}\\])} $data {\\\1} dataP	set n [regsub -all $MarkupDeclExpr $dataP $MarkupDeclSub dataP]	if {$n} {	    set progress 1	    # All but the last markup declaration should have no text	    set dataP [lrange "{} {} \{$dataP\}" 3 end]	    if {[llength $dataP] > 3} {		foreach {decl value text} [lrange $dataP 0 [expr [llength $dataP] - 4]] {		    ParseDTD:EntityMode [array get options] mode replText decl value text $delimiter $name $param		    ParseDTD:ProcessMarkupDecl [array get options] decl value delimiter name mode repltextVar text param		    if {[string length [string trim $text]]} {			# check for conditional section close			if {[regexp {]]>(.*)$} $text discard text]} {			    if {[string length [string trim $text]]} {				uplevel #0 $options(-errorcommand) [list unexpectedtext "unexpected text \"$text\""]			    }			    if {![llength $state(condSections)]} {				uplevel #0 $options(-errorcommand) [list illegalsection "extraneous conditional section close"]			    }			    set state(condSections) [lreplace $state(condSections) end end]			    if {![string compare $mode "ignore"]} {				set mode {} ;# normal			    }			} else {			    uplevel #0 $options(-errorcommand) [list unexpectedtext "unexpected text \"$text\""]			}		    }		}	    }	    # Do the last declaration	    foreach {decl value text} [lrange $dataP [expr [llength $dataP] - 3] end] {		ParseDTD:EntityMode [array get options] mode replText decl value text $delimiter $name $param		ParseDTD:ProcessMarkupDecl [array get options] decl value delimiter name mode repltextVar text param	    }	}	# Now expand the PE reference, if any	switch -glob $mode,[string length $PEref],$n {	    ignore,0,* {		set dtd $text	    }	    ignore,*,* {		set dtd $text$remainder	    }	    *,0,0 {		set dtd $data	    }	    *,0,* {		set dtd $text	    }	    *,*,0 {		if {[catch {append data $PEnts($PEref)}]} {		    if {[info exists ExtPEnts($PEref)]} {			set externalParser [$options(-cmd) entityparser]			$externalParser parse $ExtPEnts($PEref) -dtdsubset external			#$externalParser free		    } else {			uplevel #0 $options(-errorcommand) [list entityundeclared "parameter entity \"$PEref\" not declared"]		    }		}		set dtd $data$remainder	    }	    default {		if {[catch {append text $PEnts($PEref)}]} {		    if {[info exists ExtPEnts($PEref)]} {			set externalParser [$options(-cmd) entityparser]			$externalParser parse $ExtPEnts($PEref) -dtdsubset external			#$externalParser free		    } else {			uplevel #0 $options(-errorcommand) [list entityundeclared "parameter entity \"$PEref\" not declared"]		    }		}		set dtd $text$remainder	    }	}	# Check whether a conditional section has been terminated	if {[regexp {^(.*?)]]>(.*)$} $dtd discard t1 t2]} {	    if {![regexp <.*> $t1]} {		if {[string length [string trim $t1]]} {		    uplevel #0 $options(-errorcommand) [list unexpectedtext "unexpected text \"$t1\""]		}		if {![llength $state(condSections)]} {		    uplevel #0 $options(-errorcommand) [list illegalsection "extraneous conditional section close"]		}		set state(condSections) [lreplace $state(condSections) end end]		if {![string compare $mode "ignore"]} {		    set mode {} ;# normal		}		set dtd $t2		set progress 1	    }	}	if {!$progress} {	    # No parameter entity references were found and 	    # the text does not contain a well-formed markup declaration	    # Avoid going into an infinite loop	    upvar #0 $options(-errorcommand) [list syntaxerror "external entity does not contain well-formed markup declaration"]	    break	}    }    set state(inInternalDTD) $oldState    # Check that conditional sections have been closed properly    if {[llength $state(condSections)] > $startCondSectionDepth} {	uplevel #0 $options(-errorcommand) [list syntaxerror "[lindex $state(condSections) end] conditional section not closed"]    }    if {[llength $state(condSections)] < $startCondSectionDepth} {	uplevel #0 $options(-errorcommand) [list syntaxerror "too many conditional section closures"]    }    return {}}# Procedures for handling the various declarative elements in a DTD.# New elements may be added by creating a procedure of the form# parse:DTD:_element_# For each of these procedures, the various regular expressions they use# are created outside of the proc to avoid overhead at runtime# sgml::DTD:ELEMENT --##	<!ELEMENT ...> defines an element.##	The content model for the element is stored in the contentmodel array,#	indexed by the element name.  The content model is parsed into the#	following list form:##		{}	Content model is EMPTY.#			Indicated by an empty list.#		*	Content model is ANY.#			Indicated by an asterix.#		{ELEMENT ...}#			Content model is element-only.#		{MIXED {element1 element2 ...}}#			Content model is mixed (PCDATA and elements).#			The second element of the list contains the #			elements that may occur.  #PCDATA is assumed #			(ie. the list is normalised).## Arguments:#	opts	configuration options#	name	element GI#	modspec	unparsed content model specificationproc sgml::DTD:ELEMENT {opts name modspec} {    variable Wsp    array set options $opts    upvar #0 $options(elementdecls) elements    if {$options(-validate) && [info exists elements($name)]} {	eval $options(-errorcommand) [list elementdeclared "element \"$name\" already declared"]    } else {	switch -- $modspec {	    EMPTY {	    	set elements($name) {}		uplevel #0 $options(-elementdeclcommand) $name {{}}	    }	    ANY {	    	set elements($name) *		uplevel #0 $options(-elementdeclcommand) $name *	    }	    default {		# Don't parse the content model for now,		# just pass the model to the application		if {0 && [regexp [format {^\([%s]*#PCDATA[%s]*(\|([^)]+))?[%s]*\)*[%s]*$} $Wsp $Wsp $Wsp $Wsp] discard discard mtoks]} {		    set cm($name) [list MIXED [split $mtoks |]]		} elseif {0} {		    if {[catch {CModelParse $state(state) $value} result]} {			eval $options(-errorcommand) [list element? $result]		    } else {			set cm($id) [list ELEMENT $result]		    }		} else {		    set elements($name) $modspec		    uplevel #0 $options(-elementdeclcommand) $name [list $modspec]		}	    }	}    }}# sgml::CModelParse --##	Parse an element content model (non-mixed).#	A syntax tree is constructed.#	A transition table is built next.##	This is going to need alot of work!## Arguments:#	state	state array variable#	value	the content model data## Results:#	A Tcl list representing the content model.proc sgml::CModelParse {state value} {    upvar #0 $state var    # First build syntax tree    set syntaxTree [CModelMakeSyntaxTree $state $value]    # Build transition table    set transitionTable [CModelMakeTransitionTable $state $syntaxTree]    return [list $syntaxTree $transitionTable]}# sgml::CModelMakeSyntaxTree --##	Construct a syntax tree for the regular expression.##	Syntax tree is represented as a Tcl list:#	rep {:choice|:seq {{rep list1} {rep list2} ...}}#	where:	rep is repetition character, *, + or ?. {} for no repetition#		listN is nested expression or Name## Arguments:#	spec	Element specification## Results:#	Syntax tree for element spec as nested Tcl list.##	Examples:#	(memo)#		{} {:seq {{} memo}}#	(front, body, back?)#		{} {:seq {{} front} {{} body} {? back}}#	(head, (p | list | note)*, div2*)#		{} {:seq {{} head} {* {:choice {{} p} {{} list} {{} note}}} {* div2}}#	(p | a | ul)+#		+ {:choice {{} p} {{} a} {{} ul}}proc sgml::CModelMakeSyntaxTree {state spec} {    upvar #0 $state var    variable Wsp    variable name    # Translate the spec into a Tcl list.    # None of the Tcl special characters are allowed in a content model spec.    if {[regexp {\$|\[|\]|\{|\}} $spec]} {	return -code error "illegal characters in specification"    }    regsub -all [format {(%s)[%s]*(\?|\*|\+)?[%s]*(,|\|)?} $name $Wsp $Wsp] $spec [format {%sCModelSTname %s {\1} {\2} {\3}} \n $state] spec    regsub -all {\(} $spec "\nCModelSTopenParen $state " spec    regsub -all [format {\)[%s]*(\?|\*|\+)?[%s]*(,|\|)?} $Wsp $Wsp] $spec [format {%sCModelSTcloseParen %s {\1} {\2}} \n $state] spec    array set var {stack {} state start}    eval $spec    # Peel off the outer seq, its redundant    return [lindex [lindex $var(stack) 1] 0]}# sgml::CModelSTname --##	Processes a name in a content model spec.## Arguments:#	state	state array variable#	name	name specified#	rep	repetition operator#	cs	choice or sequence delimiter## Results:#	See CModelSTcp.proc sgml::CModelSTname {state name rep cs args} {    if {[llength $args]} {	return -code error "syntax error in specification: \"$args\""    }    CModelSTcp $state $name $rep $cs}# sgml::CModelSTcp --##	Process a content particle.## Arguments:#	state	state array variable#	name	name specified#	rep	repetition operator#	cs	choice or sequence delimiter## Results:#	The content particle is added to the current group.proc sgml::CModelSTcp {state cp rep cs} {    upvar #0 $state var    switch -glob -- [lindex $var(state) end]=$cs {	start= {	    set var(state) [lreplace $var(state) end end end]	    # Add (dummy) grouping, either choice or sequence will do	    CModelSTcsSet $state ,	    CModelSTcpAdd $state $cp $rep	}	:choice= -	:seq= {	    set var(state) [lreplace $var(state) end end end]	    CModelSTcpAdd $state $cp $rep	}	start=| -	start=, {	    set var(state) [lreplace $var(state) end end [expr {$cs == "," ? ":seq" : ":choice"}]]	    CModelSTcsSet $state $cs	    CModelSTcpAdd $state $cp $rep	}	:choice=| -	:seq=, {	    CModelSTcpAdd $state $cp $rep	}	:choice=, -	:seq=| {	    return -code error "syntax error in specification: incorrect delimiter after \"$cp\", should be \"[expr {$cs == "," ? "|" : ","}]\""	}	end=* {	    return -code error "syntax error in specification: no delimiter before \"$cp\""	}	default {	    return -code error "syntax error"	}    }    }# sgml::CModelSTcsSet --##	Start a choice or sequence on the stack.## Arguments:#	state	state array#	cs	choice oir sequence## Results:#	state is modified: end element of state is appended.proc sgml::CModelSTcsSet {state cs} {    upvar #0 $state var    set cs [expr {$cs == "," ? ":seq" : ":choice"}]    if {[llength $var(stack)]} {	set var(stack) [lreplace $var(stack) end end $cs]    } else {	set var(stack) [list $cs {}]    }}# sgml::CModelSTcpAdd --##	Append a content particle to the top of the stack.## Arguments:#	state	state array#	cp	content particle#	rep	repe

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?