There are many schemes for defining the semantics of programming languages:
denotational semantics (which maps syntax into functions that compute program state);
operational semantics (which amounts to building interpreters for your language),
transformational semantics (which amounts to translating your languauge to another
language for which some other semantics already exists), etc.
Very few of them presently lead to systems usable for real programming languages. One of the other answers here suggests Centaur as a system that tries to do this.
Action semantics by Peter Mosses is one of the more serious recent attempts.
For real systems, rather more ad hoc methods are presently the most effective.
These inlude systems in which the lexical and grammatical syntax can be effectively
defined (as variants of LEX and YACC), and automatically build trees.
Attribute grammars allow the specification of computations over trees,
which allow one to define some kinds of analyses, such as symbol table
construction or metrics (technically you could
do denotational semantics this way). Most conventional languages (C, Java, C#,
COBOL, ...) all have relatively similar structures regarding control flow and
data flow, and as a consequence one can build generic flow analysis routines
to allow one to reason about such standard languages.
Finally, you need a purpose for your semantic analysis: what facts
exactly do you want to extract? The available static analysis
systems have hybrid pattern-driven/procedural code methods for
collecting the syntax, symbol-table, and flow facts of interest
to compute specific answers to specific questions.
Some systems enable one to use this semantic information to carry
source code modification.
One system that follows the more ad hoc approach above is our
DMS Software Reengineering Toolkit, which also has the generic semantic defintions
(syntax, symbol tables, data flow anlaysis) completed for real
languages such as Java, C, C++ and COBOL. DMS can apply
source-to-source transformations to the ASTs conditioned
by various fact-collecting procedures, and this enables mass
transformation of code in a reliable way.